0

I have a frontend vue site hosted on google's firebase with the url (https://front-end.web.com) , while my flask backend is hosted on heroku with the url (https://back-end.heroku.com). This makes my session not to persist across requests, I tried fixing this by implementing CORS on my backend, but for some reason it's not working , below are snippets of my code to show my implementation

config_class.py

class ConfigClass():
    CORS_ALLOW_HEADERS = ['Content-Type']
    CORS_ORIGINS = ['https://front-end.web.com']
    SECRET_KEY = os.environ.get("APP_SECRET_KEY")
    SESSION_TYPE = 'redis'

_init.py

from flask import Flask, session
from flask_session import Session
from flask_cors import CORS


from root_folder.config import ConfigClass


db = SQLAlchemy() 
migrate = Migrate() 
ma = Marshmallow()  
sess = Session()


def create_app(ConfigClass):

    # initiate the flask app and assign the configurations #
    app = Flask(__name__)
    app.config.from_object(config_options[config_class])
    sess.init_app(app)

    from root_folder.clients import clients_app

    # register all the blueprints in this application
    app.register_blueprint(clients_app)

    CORS(app, supports_credentials=True)

    # return the app object to be executed
    return app

app.py

from root_folder import create_app

app = create_app()

Procfile:

web: gunicorn -w 1 app:app

axios front end request

let formData = new FormData();
formData.append("email", email);
formData.append("password", password);

axios.post(
                backendUrl+'create_client_account',
                formData,
                {
                    withCredentials: true,
                    headers:{
                       "Content-Type": "multipart/form-data"
                    }
                }
);

create client route ( I have stripped this code block to the bare minimum to make it understandable):

from flask import session

# route for creating account credentials
@bp_auth_clients_app.route("/create_client", methods=["POST"])
def create_client():
    
    username = request.form.get("username").lower()
    email = request.form.get("email").lower()

    
    # create account code goes here  #
    
    auth_authentication = True

    session["auth_authentication"] = auth_authentication

    req_feedback = {
            "status": True,
            "message": "Account was successfully created",
            "data": feedback_data
    }

    return jsonify(req_feedback), 200

After the account is successfully created, I am unable to access the session value in subsequent requests, it returns None.

To recreate the problem on my local server, I access the front-end via the domain "localhost:8080" , while I access the flask server via "127.0.0.1:8000" . If I change the front end domain to "127.0.0.1:8080", I don't usually have any problems.

Kindly advice on what to do.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
ebuoe
  • 109
  • 2
  • 12

2 Answers2

2

Thanks to Ahmad's suggestion, I was able to resolve the issue using custom domains for both my frontend and backend as follows:

frontend.herokuapp.com -> customDomain.com
backend.herokuapp.com -> api.customDOmain.com 

finally I added the line below to my session config:

SESSION_COOKIE_DOMAIN = ".customDomain.com"

And all was well and good.

ebuoe
  • 109
  • 2
  • 12
  • Hello, would you be able to update your full config for the session? I'm trying to achieve the same result as you (kind of); sharing cookies between www.example.com and api.example.com – jeff Apr 28 '22 at 18:49
1

Sessions use cookies: On session creation the server will send the cookie value in the set-cookie header. It doesn't work for you because of cross origin issue.

It works fine for you when you use 127.0.0.1 because 127.0.0.1:8080 and 127.0.0.1:8000 are the same origin so the browser accepts the set-cookie header and do set the cookie no problem.

Cookies are sent in the header on each request and your server loads the session from Redis by cookie value (The cookie value is called session_id).
How it gets inserted => Normally your session gets serialized and inserted in Redis with the cookie hash as Key in the end of the request life cycle.

If you want to keep using sessions and cookies you need to find another solution for your deployment to so that your backend and frontend have the same hostname.

If you can't do I'd recommend to read about JWT (Json-Web-Tokens).

EDIT You can send the session id in your response body and save it in local storage.

Then you need to configure: frontend set the session id value it in the Authorization header base64 encoded. Backend base64 decode Authorization header value from request and check for the session in Redis, if exists load it.

EDIT

How to deploy both backend/frontend on same hostname using apache: using apache you need to create 2 virtual hosts one for backend and the other for frontend listening on different ports then configure your web server deployment to use the backend VH if the path is prefixed by /api/ and use the frontend Virtual host for anything else. This way any request you make to your api your backend will handle it otherwise it'll serve your frontend app. This is just a way on how to do it there is plenty others Check this question.

Ahmed Jaouadi
  • 213
  • 3
  • 10
  • Thank you for your feedback. I took your advice and hosted my front end on heroku, so that both frontend & backend can share the same domain on heroku as follows: frontend.herokuapp.com ; backend.herokuapp.com. However I'm still having the same issues with my sessions online – ebuoe Jan 08 '22 at 00:36
  • backend.herokuapp.com and frontend.herokuapp.com have different hostnames. The case of `127.0.01` was working because the hostname was the same but different port See my edited answer for more details. – Ahmed Jaouadi Jan 08 '22 at 02:20
  • @e_green check my comment and edited answer. – Ahmed Jaouadi Jan 08 '22 at 11:42
  • 1
    Thanks for your help. your insight was instrumental in helping me solve the problem, using custom domains. – ebuoe Jan 08 '22 at 20:53
  • @AhmedJaouadi Hello, would this also apply to subdomains too? Say for example you have: www.example.com and api.example.com. From www.example.com, a request is made to api.example.com, would the cookie be sent (and set) to www.example.com? – jeff Apr 28 '22 at 18:46