Hi,
I have a strange issue with Play (2.8.5) not setting the CSRF protection related Set-Cookie header during initial loading of index.html page. Strangely this happens only when running Play in production mode. The index page is served as public asset and it’s just a plain html page so we’re not talking about twirl templates here. Route is configured like this:
GET / controllers.FrontendRouterController.index()
and the implementation is this:
import controllers.Assets
import play.api.{Environment, Mode}
import play.api.mvc.{Action, AnyContent, InjectedController}
import javax.inject.Inject
class FrontendRouterController @Inject()(assets: Assets, env: Environment)
extends InjectedController {
def index(): Action[AnyContent] = env.mode match {
case Mode.Dev => assets.at("dev-index.html")
case _ => assets.at("index.html")
}
}
Now if I change the index method to return e.g. Ok("hello")
then in the response I can see that there’s
Set-Cookie: XSRF-TOKEN=c66634c57521d3b362fe2a86a0b170ed357fe978-1613731879064-98752d2871f30dc02c98271a; SameSite=Lax; Path=/
but when using the built-in Assets controller to return the response then this header does not get added. Of course this leads to client not being able to provide the token in future requests. Is this some known issue with public assets that CSRF token is not inserted automatically?
Here’s the filter configuration:
play.filters.csrf.header.name = "X-XSRF-TOKEN"
play.filters.csrf.cookie.name = "XSRF-TOKEN"
play.filters.csrf.header.protectHeaders = null
The client is an Angular 8 single page app if that makes any difference. We used to serve the index page as a Play template like this: Ok(views.html.index.render())
but switched to this public asset approach recently because it works better with our frontend tooling (webpack mostly).