CORS Support Akka-http

4,544 views
Skip to first unread message

Ganta Murali Krishna

unread,
Mar 10, 2015, 10:14:53 AM3/10/15
to akka...@googlegroups.com
Hello,

I am currently experimenting with Akka-http on one of our modules. Below (or attached) is my current CORS file for spray. I am struggling with conversion, for e.g.: I cant find alternative to mapRequestContext. Can any help me to rewrite/convert this please. So I can use this with akka-http. Any help is appreciated.

Regards
Murali

import spray.http.{HttpMethods, HttpMethod, HttpResponse, AllOrigins}
import spray.http.HttpHeaders._
import spray.http.HttpMethods._
import spray.routing._

trait CORSSupport {
this: HttpService =>
private val allowOriginHeader = `Access-Control-Allow-Origin`(AllOrigins)
private val optionsCorsHeaders = List(
`Access-Control-Allow-Headers`("Origin, X-Requested-With,Authorization,Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent,apiKey"),
`Access-Control-Max-Age`(1728000))

def cors[T]: Directive0 = mapRequestContext { ctx => ctx.withRouteResponseHandling({
//It is an option requeset for a resource that responds to some other method
case Rejected(x) if (ctx.request.method.equals(HttpMethods.OPTIONS) && !x.filter(_.isInstanceOf[MethodRejection]).isEmpty) => {
val allowedMethods: List[HttpMethod] = x.filter(_.isInstanceOf[MethodRejection]).map(rejection => {
rejection.asInstanceOf[MethodRejection].supported
})
ctx.complete(HttpResponse().withHeaders(
`Access-Control-Allow-Methods`(OPTIONS, allowedMethods: _*) :: allowOriginHeader ::
optionsCorsHeaders
))
}
}).withHttpResponseHeadersMapped { headers =>
allowOriginHeader :: headers
}
}
}
CORSSupport.scala

Tim Pigden

unread,
Mar 10, 2015, 1:48:09 PM3/10/15
to akka...@googlegroups.com
This thread may help:

I've not got around to looking at it yet.

Mariano Treb

unread,
Jun 17, 2015, 10:34:50 AM6/17/15
to akka...@googlegroups.com
I am having the same problem!!! How did you solved it? I have been working for days and I cant find any good solution.

Tim Pigden

unread,
Jun 17, 2015, 12:33:32 PM6/17/15
to akka-user@googlegroups com

I'll get my colleague to post something
He did the work

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/5RCZIJt7jHo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

yar....@gmail.com

unread,
Jun 18, 2015, 12:23:50 PM6/18/15
to akka...@googlegroups.com
Hi,

I didn't find a counterpart of mapRequestContext in akka-http, so I just allow all the methods I have in my route. Here is my shot at CORS in akka-http:

import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.model.headers._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{AuthenticationFailedRejection, Directive0, RejectionHandler, Route}
import com.typesafe.config.ConfigFactory

trait CorsSupport {
lazy val allowedOrigin = {
val config = ConfigFactory.load()
val sAllowedOrigin = config.getString("cors.allowed-origin")
HttpOrigin(sAllowedOrigin)
}

//this directive adds access control headers to normal responses
private def addAccessControlHeaders: Directive0 = {
mapResponseHeaders { headers =>
`Access-Control-Allow-Origin`(allowedOrigin) +:
`Access-Control-Allow-Credentials`(true) +:
`Access-Control-Allow-Headers`("Authorization", "Content-Type", "X-Requested-With") +:
headers
}
}

//this handles preflight OPTIONS requests. TODO: see if can be done with rejection handler,
//otherwise has to be under addAccessControlHeaders
private def preflightRequestHandler: Route = options {
complete(HttpResponse(200).withHeaders(
`Access-Control-Allow-Methods`(OPTIONS, POST, PUT, GET, DELETE)
)
)
}

def corsHandler(r: Route) = addAccessControlHeaders {
preflightRequestHandler ~ r
}
}

you may notice I take allowed origin from the config file option "cors.allowed-origin". I mix this trait into my class which contains a route I want to handle CORS and wrap the route into corsHandler like so:
corsHandler {
path("") { ... }
}

Austin Guest

unread,
Aug 16, 2015, 3:07:21 AM8/16/15
to Akka User List
Great implementation `yar...`!

Question: I borrowed this code in my own implementation but ran into an odd problem where it worked just fine on the preflight `OPTIONS` request, but then omitted the CORS headers from the subsequent `POST` that was getting preflighted, causing the request to be rejected with a 400 Error. ("No 'Access-Control-Allow-Origin' header is present on the requested resource.' etc...)

Here's my version of your impl:
https://github.com/the-learning-collective/whereat-server/blob/dev/src/main/scala/routes/CorsSupport.scala

And here's me using it:
https://github.com/the-learning-collective/whereat-server/blob/master/src/main/scala/routes/Routes.scala#L24


Any idea why I'm getting this error?

I'm using superagent on the client side (which someone had this CORS-related issue with, but I think that's a red-herring, since I very much want/need my `content-type` to be `application/json`, unlike this user and the proposed solution he winds up being offered.)

Yar Ilich

unread,
Aug 16, 2015, 5:12:29 AM8/16/15
to akka...@googlegroups.com
Hi,

pleasure to be of use. I got confused: did client part omit headers from POST request? Where did you get the message "No 'Access-Control-Allow-Origin' header is present on the requested resource." from? The problem may be some caveats of using Access-Control-Allow-Origin. See http://www.webdavsystem.com/ajax/programming/cross_origin_requests, specifically the first Important! box.

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/5RCZIJt7jHo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--
Sincerely,
Yar Illich

Austin Guest

unread,
Aug 17, 2015, 4:40:42 PM8/17/15
to Akka User List
Hi Yar. Thanks for getting back! The error message was regarding headers missing from the *server's* response to the actual POST request (it handled the "pre-flight" OPTIONS request just fine, which is why I was puzzled.

I've since resolved the question, as it was a matter (as the blog you linked to helpfully pointed out) of the wildcard `*` as a value for the `Allow-Access-Origin` header being incompatible with setting `Allow-Access-Credentials` to `true`. I temporarily resolved the issue by disabling access credentials. Thanks for pointing me in the right direction! :)

Not the best long-term fix, but necessary for the time being as a workaround for running locally (since I will always have the origin 'localhost'. As a longer term fix, I plan on using Chrome's Allow-Access-Origin Dev Tools add-on, which spoofs a '*' header for running locally -- just as soon as I can figure out how to get my webpack dev server to disable credentials so the the Allow-Access headers won't conflict.

If anyone's stuck on a similar problem and is interested in results, I'm happy to post them here. (Though that set of problem solving would belong more properly on a React mailing list than one pertaining to akka-http! :P)

/a/

Patrick Ting

unread,
Sep 22, 2015, 7:47:36 AM9/22/15
to Akka User List
Hi Everyone,

I ended up porting and modifying Ganta's original CORS support with an existing one I had that I pulled from the Spray mailing list awhile back and posted it here: https://gist.github.com/pcting/2e65c36f868c5cee7d6a

The most frustrating part was finding a way around the loss of RequestContext.withRouteResponseHandling and RequestContext.withHttpResponseHeadersMapped.

Please fork it, poke holes int it, and send feedback!

Cheers,
Patrick

Patrik Nordwall

unread,
Sep 25, 2015, 10:20:07 AM9/25/15
to akka...@googlegroups.com
Thanks for sharing, Patrick.

You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.

To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--

Patrik Nordwall
Typesafe Reactive apps on the JVM
Twitter: @patriknw

Filippo De Luca

unread,
Oct 6, 2015, 5:47:18 AM10/6/15
to akka...@googlegroups.com
Hi,
This implementation works fine. But it does not handle a case in which a CORS request has been rejected. The headers are not set on the rejection handler.

I don't know if it is an expected behavior or not. If so how we can wrap an existing RejectionHandler to add headers to all the cases?

Thanks.

tdroz...@exceda.com

unread,
Feb 3, 2016, 4:25:40 PM2/3/16
to Akka User List
Seems like as of akka-http 2.0.3 the pre-flight OPTIONS handling via RejectionHandler no longer works as expected - at least if you're trying to use the directive once to wrap all routes.

It appears that the behavior of akka-http is to only return the first HttpMethod that was rejected - even if all of them were.  As a result, we only are handed the first one - usually GET in the Access-Control-Allow-Methods header, so it looks like:

 Access-Control-Allow-Methods OPTIONS, GET

Which for the following PUT, POST, etc isn't really valid...

Lomig Mégard

unread,
Mar 16, 2016, 5:16:41 PM3/16/16
to Akka User List
Hi,

Jumping in this thread to share the akka-http CORS implementation I have been working on recently:

https://github.com/lomigmegard/akka-http-cors

The goal was to follow the recommendation from W3C (https://www.w3.org/TR/cors/) and be still easy to use. Not production ready as I would like to write more tests and do some benchmarks.

Let me know if you would be interested to have this published to maven. And don't hesitate to open an issue to motivate me :)

Cheers,
Lomig

Konrad Malawski

unread,
Mar 16, 2016, 5:22:32 PM3/16/16
to akka...@googlegroups.com, Lomig Mégard
Thanks for sharing Lomig!
I only skimmed through so far but looks very good already!

I've added it to my board of things to look at in detail, it's a bit long but I hope to get there eventually! 

You can also add it to the akka.io/community page so people can find it from there :-)
(We aim to revamp this site soon-ish).

-- 
Cheers,
Konrad 'ktoso’ Malawski
Akka @ Lightbend

Fiona Boyle

unread,
Jun 17, 2016, 6:44:47 AM6/17/16
to Akka User List, lomig....@gmail.com
Thank you to everyone who ask been answering these questions.  I am trying to implement CORS support in Akka Http, but I am not sure how to specify any origin.  The code above uses
val sAllowedOrigin = config.getString("cors.allowed-origin")
but I cannot find out what should be in this string (this config value does not exist on my system).  I have tried various forms of `*` without success.  Any help gratefully received.
Thanks
Fiona Treveil

Lomig Mégard

unread,
Jun 17, 2016, 3:53:53 PM6/17/16
to Akka User List
Hi Fiona,

The simplest way to enable CORS with akka-http is to use the akka-http-cors library:
https://github.com/lomigmegard/akka-http-cors

Look at the README for some basic examples. You can change the default settings, including the allowed origins.

val settings = CorsSettings.defaultSettings.copy(allowedOrigins = HttpOriginRange.*)
val route: Route = cors(settings) {
  complete
(...)
}

You can create an issue directly in the GitHub repo if you have more questions.

Bests,
Lomig

Fiona Boyle

unread,
Jun 18, 2016, 4:37:05 PM6/18/16
to akka...@googlegroups.com
Thank you for the quick reply.  I will try this out.

Best wishes
Fiona

Matan Safriel

unread,
Jul 14, 2016, 9:26:01 AM7/14/16
to Akka User List
Any built-in support for CORS by now?

Konrad Malawski

unread,
Jul 14, 2016, 9:27:12 AM7/14/16
to akka...@googlegroups.com, Matan Safriel
Use the community provided ones.
There's no need for us to ship one if community has stepped up and provided libraries, as is the case here I believe :-)

-- 

Konrad `ktoso` Malawski
Akka @ Lightbend
Reply all
Reply to author
Forward
0 new messages