user2040800
user2040800

Reputation: 227

CORS failure in with Python Falcon even with heads for Auth Pre-Flight

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.

Upvotes: 5

Views: 2788

Answers (3)

kartoon
kartoon

Reputation: 1194

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'

Upvotes: 1

Nam G VU
Nam G VU

Reputation: 35384

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])

Upvotes: 1

user2040800
user2040800

Reputation: 227

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])

Upvotes: 7

Related Questions