Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting cors errors in Scala Play Framework v2.6.x

Tags:

I'm trying to get around a CORS error for a simple "hello world" style REST API in Scala/Play 2.6.x and I have tried everything that I can think of at this point. As far as I can tell there is not a good solution or example to be found on the internet, so even if this should be an easy fix then anyone that has a good solution would really help me out by posting it in full. I am simply trying to send a post request from localhost:3000 (a react application using axios) to localhost:9000 where my Scala/Play framework lives.

THE ERRORS

The error that I am getting on the client-side is the following:

XMLHttpRequest cannot load http://localhost:9000/saveTest.
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 403.

The error that I am getting on the server-side is

success] Compiled in 1s

--- (RELOAD) ---

[info] p.a.h.EnabledFilters - Enabled Filters
(see <https://www.playframework.com/documentation/latest/Filters>):

    play.filters.csrf.CSRFFilter
    play.filters.headers.SecurityHeadersFilter
    play.filters.hosts.AllowedHostsFilter
    play.filters.cors.CORSFilter

[info] play.api.Play - Application started (Dev)
[warn] p.f.c.CORSFilter - Invalid CORS
request;Origin=Some(http://localhost:3000);
Method=OPTIONS;Access-Control-Request-Headers=Some(content-type)

MY CODE

I have the following in my application.conf file

# https://www.playframework.com/documentation/latest/Configuration

play.filters.enabled += "play.filters.cors.CORSFilter"

play.filters.cors {
  pathPrefixes = ["/"]
  allowedOrigins = ["http://localhost:3000", ...]
  allowedHttpMethods = ["GET", "POST", "PUT", "DELETE"]
  allowedHttpHeaders = ["Accept"]
  preflightMaxAge = 3 days
}

I've tried changing pathPrefixes to /saveTest (my endpoint), and tried changing allowedOrigins to simply 'https://localhost'. I've tried changing allowedHttpHeaders="Allow-access-control-allow-origin". I've tried setting allowedOrigins, allowedHttpMethods, and allowedHttpHeaders all to null which, according to the documentation (https://www.playframework.com/documentation/2.6.x/resources/confs/filters-helpers/reference.conf) should allow everything (as should pathPrefixes=["/"]

My build.sbt is the following, so it should be adding the filter to the libraryDependencies:

name := """scalaREST"""
organization := "com.example"

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.12.2"

libraryDependencies += guice
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.0" % Test
libraryDependencies += filters

According to documentation available here: https://www.playframework.com/documentation/2.6.x/Filters#default-filters you can set the default filters like this:

import javax.inject.Inject

import play.filters.cors.CORSFilter
import play.api.http.{ DefaultHttpFilters, EnabledFilters }

class Filters @Inject()(enabledFilters: EnabledFilters, corsFilter: CORSFilter)
  extends DefaultHttpFilters(enabledFilters.filters :+ corsFilter: _*)

I'm not sure exactly where that should go in my project - it doesn't say, but from other stackoverflow answers I kind of assume it should go in the root of my directory (that is /app). So that's where I put it.

Finally, there was one exotic stackoverflow response that said to put this class in my controllers and add it as a function to my OK responses

  implicit class RichResult (result: Result) {
    def enableCors =  result.withHeaders(
      "Access-Control-Allow-Origin" -> "*"
      , "Access-Control-Allow-Methods" -> 
        "OPTIONS, GET, POST, PUT, DELETE, HEAD"
        // OPTIONS for pre-flight
      , "Access-Control-Allow-Headers" -> 
        "Accept, Content-Type, Origin, X-Json, 
        X-Prototype-Version, X-Requested-With"
        //, "X-My-NonStd-Option"
      , "Access-Control-Allow-Credentials" -> "true"
    )
  }

Needless to say, this did not work.

WRAP UP

Here is the backend for my current scala project.

https://github.com/patientplatypus/scalaproject1/tree/master/scalarest

Please, if you can, show a full working example of a CORS implementation - I cannot get anything I can find online to work. I will probably be submitting this as a documentation request to the Play Framework organization - this should not be nearly this difficult. Thank you.

like image 213
Peter Weyand Avatar asked Aug 08 '17 02:08

Peter Weyand


People also ask

How do I fix the CORS error?

Cross-Origin Resource Sharing (CORS) errors occur when a server doesn't return the HTTP headers required by the CORS standard. To resolve a CORS error from an API Gateway REST API or HTTP API, you must reconfigure the API to meet the CORS standard.

Why is CORS an issue?

The CORS behavior, commonly termed as CORS error, is a mechanism to restrict users from accessing shared resources. This is not an error but a security measure to secure users or the website which you are accessing from a potential security bleach.

What is CORS error status code?

If CORS processing fails, the web reverse proxy returns an error response with the CORS error code. Create or modify the corresponding template for error code 38983672 to customize the response returned. By default, IBM Security Verify Access installs a HTML type error template which returns a 400 status code.

What is CORS filter?

Play provides a filter that implements Cross-Origin Resource Sharing (CORS). CORS is a protocol that allows web applications to make requests from the browser across different domains.


2 Answers

Your preflight request fails because you have a Content-Type header set

Add content-type to allowedHttpHeaders in your application.conf like so

#application.conf

play.filters.cors {
  #other cors configuration
  allowedHttpHeaders = ["Accept", "Content-Type"]
} 
like image 175
Salailah Avatar answered Sep 30 '22 01:09

Salailah


I had this problem too and I added these code in application.conf

play.filters.enabled += "play.filters.cors.CORSFilter"
play.filters.cors {
  allowedHttpMethods = ["GET", "HEAD", "POST"]
  allowedHttpHeaders = ["Accept", "Content-Type"]"
}

and now everything is OK!

for more info

like image 31
Majid Hosseini Avatar answered Sep 30 '22 01:09

Majid Hosseini