5

Receiving these error when using the OPTIONS verb in Angular2 http.get(url, options), even though the appropriate CORS headers are set in Falcon Rest API.

XMLHttpRequest cannot load http://localhost:8000/names. Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.

resp.set_header("Access-Control-Allow-Origin", "*")
        resp.set_header("Access-Control-Allow-Credentials", "true")
        resp.set_header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT")
        resp.set_header("Access-Control-Allow-Headers",
                       "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers")

For non OPTIONS / normal http.get() requests this works fine.

user2040800
  • 227
  • 4
  • 14
  • Looks like these OPTIONS requests from Angular need to be appropriately handles by falcon? https://stackoverflow.com/questions/6660019/restful-api-methods-head-options – user2040800 Mar 10 '17 at 09:50
  • Same issue for me. I have to set all to True for `allow_origins_list` , `allow_all_methods`, `allow_all_headers` – Nam G VU Feb 03 '20 at 09:10

3 Answers3

7

Resolved this using falcon_cors, specifically by setting allow_all_methods=True

pip install falcon-cors

from falcon_cors import CORS

cors = CORS(allow_origins_list=['http://localhost:3000'],
            allow_all_headers=True,
            allow_all_methods=True)

api = falcon.API(middleware=[cors.middleware])
user2040800
  • 227
  • 4
  • 14
  • +1. I used `public_cors = CORS(allow_all_origins=True)` as shown in https://github.com/lwcolton/falcon-cors – Ryan Aug 05 '18 at 19:16
1

I tried as guided by lwcolton on github here

And also set allow_all_headers=True, allow_all_methods=True

i.e. similar to above answer https://stackoverflow.com/a/42716126/248616 but two more params to add

from falcon_cors import CORS

cors = CORS(
    allow_all_origins=True,
    allow_all_headers=True,
    allow_all_methods=True,
)

api = falcon.API(middleware=[cors.middleware])
Nam G VU
  • 33,193
  • 69
  • 233
  • 372
1

I'll suggest to go through documentation for this.

Also, resp.set_header('Access-Control-Allow-Origin', '*') is not a good practice to follow in production. Have some whitelisted origins and methods and based on the request, if coming from whitelisted origin then you can put the same origin in here resp.set_header('Access-Control-Allow-Origin', req.headers["ORIGIN"]).

Below is the code I prefer-

whitelisted_origins = ["http://localhost:4200"]
whitelisted_methods = ["GET", "POST", "OPTIONS"]

class CORSComponent:

    def process_request(self, req, resp):
        success = False
        # validate request origin
        if ("ORIGIN" in req.headers):
            # validate request origin
            if (req.headers["ORIGIN"] in whitelisted_origins):
                # validate request method
                if (req.method in whitelisted_methods):
                    success = True
                else:
                    # you can put required resp.status and resp.media here
                    pass
            else:
                # you can put required resp.status and resp.media here
                pass
        else:
            # you can put required resp.status and resp.media here
            pass
        if success:
            resp.set_header('Access-Control-Allow-Origin', req.headers["ORIGIN"])
        else:
            # exit request
            resp.complete = True

    def process_response(self, req, resp, resource, req_succeeded):
        if (req_succeeded and
            "ORIGIN" in req.headers and
            and req.method == 'OPTIONS'
            and req.get_header('Access-Control-Request-Method')
        ):
            # NOTE: This is a CORS preflight request. Patch the response accordingly.

            allow = resp.get_header('Allow')
            resp.delete_header('Allow')

            allow_headers = req.get_header(
                'Access-Control-Request-Headers',
                default='*'
            )

            resp.set_headers((
                ('Access-Control-Allow-Methods', allow),
                ('Access-Control-Allow-Headers', allow_headers),
                ('Access-Control-Max-Age', '86400'),  # 24 hours
            ))

Once done, you can now add this to middleware like-

api = falcon.API(middleware=[
    CORSMiddleware(),
])

If you do not wish to use the above method, you can go ahead with falcon-cors.

from falcon_cors import CORS

cors = CORS(
    # allow_all_origins=False,
    allow_origins_list=whitelisted_origins,
    # allow_origins_regex=None,
    # allow_credentials_all_origins=True,
    # allow_credentials_origins_list=whitelisted_origins,
    # allow_credentials_origins_regex=None,
    allow_all_headers=True,
    # allow_headers_list=[],
    # allow_headers_regex=None,
    # expose_headers_list=[],
    # allow_all_methods=True,
    allow_methods_list=whitelisted_methods
)

api = falcon.API(middleware=[
    cors.middleware,
])

FYI, Methods supported by falcon 2.0.0 -
'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'

kartoon
  • 1,040
  • 1
  • 11
  • 24