How to set cookie from flask to reactjs

Viewed 1168

I am working on a project where I use flask as a backend and reactjs for the front-end. When I try to set a cookie from flask, the cookie is not set on the browser. I have been researching what could be wrong. I have an endpoint /login in flask where, when the user logs in from reactjs, a JWT is created and a cookie is set. My flask app is running on port 5000 and my react app is running on port 3000. During my research on this problem, I came across multiple solutions, but they still did not work, like setting CORS(app, support_credentials=True) and also including the domain keyword argument in set cookie.
Here is the code from my flask app:

# login route - this will set cookie (JWT token)
@app.route('/login', methods=['POST'])
@cross_origin()
def login():
    auth = request.authorization

    # the auth should have a username and a password
    user = User.query.filter_by(username=auth['username']).first()

    if not user:
        return jsonify({'msg': 'user not found'}), 404

    if bcrypt.check_password_hash(user.password, auth['password']):
        # generate a token
        access_token = create_access_token(identity=user.username, expires_delta=datetime.timedelta(days=1))
        
        response = make_response({'msg': 'successfully logged in!'})
        response.headers['Access-Control-Allow-Credentials'] = True
        response.set_cookie('access_token', value=access_token, domain='127.0.0.1:3000')

        # we need to convert the response object to json

        return jsonify({'response': response.json}), 200

    return jsonify({'msg': 'wrong credentials'}), 401
2 Answers

So i figured out whats wrong, before I get into the details, here are two awesome videos that explain CORS and how to work with them

Now, the above two tutorials are not flask specific, but they are pretty relatable to flask, we use the flask-cors library to allow CORS. from my code, I have a /login endpoint whereby if the user logs in, a response object is made and a cookie containing a JWT is set. The main focus here is the @cross_origin() decorator, this is what makes CORS possible, But in here we still need to set a few things, some kwargs, the most important is the support_credentials=True By default, Flask-CORS does not allow cookies to be submitted across sites, since it has potential security implications. To allow cookies or authenticated requests to be made cross origins, simply set the supports_credentials option to True. For my code, this is what I added.

@cross_origin(methods=['POST'], supports_credentials=True, headers=['Content-Type', 'Authorization'], origin='http://127.0.0.1:5500')

Of course, even after this, it still did not work and for one reason. I was not returning the actual response object that contained all the headers. From my code, the other thing I had to change was

from

return jsonify({'response': response.json}), 200

to

return response, 200

for testing purposes, I made another simple endpoint /user that simpy returns the cookie that was stored on the browser.

@app.route('/user')
@cross_origin(supports_credentials=True)
def get_user():
    response = make_response('cookie being retrieved!')
    cookie = request.cookies.get('access_token')
    return jsonify({'cookie': cookie})

It is also important to know how to configure the front-end to deal with the requests. So here is a simple javascript code I developed to test the api, using the fetch api

// for logging in a user
fetch('http://127.0.0.1:5000/login', {
                headers: {'Authorization': 'Basic ' + btoa(`${username}:${password}`)}, // the values of username and password variables are coming from a simple login form
                method: 'POST',
                mode: 'cors' // here we specify that the method is CORS meaning that the browser is allowed to make CORS requests
            })
            .then(res => res)
            .then(data => console.log(data))

// for getting the cookies - testing
                fetch('http://127.0.0.1:5000/user', {
                method: 'GET',
                mode: 'cors',
                credentials: 'include' // includes cookies, authorization in request headers
            })
            .then(res => res.json())
            .then(msg => console.log(msg))

I hope this helps somone else :)

It happend to me too, what tou need to do is to add to your package.json file on you React project

proxy : http://localhost:5000

or whenever your flask app runs on.

and then it makes the app run together and solves your problem.

now, when you fetch you need to fetch like this:

fetch("/user")

and not

fetch("http://localhost5000/user")
Related