9

I'm trying to build a api site using Flask, and I am using Flask-jwt to provide token authorization.
The authorizaiton works fine if I do CORS in Apache ( using mod_headers to add Allow-Access headers, like this

Header set Access-Control-Allow-Origin "*"

However, I want to have more detailed access control instead of just using wildcard. and I looked at flask-cors, which is a nice wrapper to check origin and send the header. And now my route looks like this (and no header manipulation in apache settings)

@app.route('/protected/place')
@cross_origin(headers=['Content-Type']) # Send Access-Control-Allow-Headers
@jwt_required()
def my_view_func():
    do something

But now I will not get the Access-Control headers response from the server if I make the http request from javascript. (However, if I manually post, like doing curl, i can still see the cross origin plugin working and the Access control headers)

When I remove the @jwt_required wrapper, the cross_origin wrapper functions fine and it will give me response. when the jwt_required wrapper is applied, no response can be seen from the server.

I'm debugging my client page with chrome. BTW

I tried to change the order of the wrappers, but it doesn't help.

Is it possible that, if the authentication fails, the cross_origin wrapper will not send the Access Control headers?

the source code of the two wrappers :
flask-jwt:
https://github.com/mattupstate/flask-jwt/blob/master/flask_jwt/init.py
flask-cors:
https://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py

Yang Hu
  • 193
  • 1
  • 8
  • 3
    After struggling for many hours, I finally found the problem. Hope it helps others who encouter the same problem. Just need to add "Authorization' to `Access-Control-Allow-Headers` if authentication is needed. Like this ``` @app.route('/protected/place') @cross_origin(headers=['Content-Type','Authorization']) # Send Access-Control-Allow-Headers @jwt_required() def my_view_func(): do something ``` – Yang Hu Jul 18 '14 at 15:07
  • Do you know way to add CORS to `/auth` handler? – Nikolay Fominyh Mar 07 '16 at 18:40
  • @YangHu Thanks for posting, very helpful, actually led me to alter how I was using the CORS extension. I found that you can do the same thing, except globally (as opposed to using the decorator on every view function) via ```CORS(app, origins="http://127.0.0.1:8080", allow_headers=["Content-Type", "Authorization", "Access-Control-Allow-Credentials"], supports_credentials=True)```. @Nikolay Fominyh If not using the extension you can just stack the decorators on a view like: ```@app.route('someurl/') @cross_origin(your config in here) @auth.login_required def some_view():... ``` – AdjunctProfessorFalcon Jan 25 '17 at 01:18

1 Answers1

8

After struggling for many hours, I finally found the problem. Hope it helps others who encouter the same problem.
Just need to include Authorization in "headers" argument (which sets the Access-Control-Allow-Headers field) when authentication is needed.
Like this

@app.route('/protected/place') 
@cross_origin(headers=['Content-Type','Authorization']) # Send Access-Control-Allow-Headers 
@jwt_required() 
def my_view_func(): 
    do something
sodimel
  • 864
  • 2
  • 11
  • 24
Yang Hu
  • 193
  • 1
  • 8
  • 1
    Glad to see you figured out a solution, sorry it took so long and was not as clear as it should be. I will add a few GOTCHAs and make sure it is clear that Authorization headers may be needed. Sadly, it is not a safe default to allow them (as it could open up a potential drive-by attack) – Cory Dolphin Aug 22 '14 at 08:17