Flask session don't persist data - python

I have a Javascript application and a Flask application. When the user send data from Js to Flask, I store it on session and it works fine at a specific route:
#app.route(...)
def user(...):
session['name'] = name
print(session['name']) # Works !
But when I tr to get the values on session from another method / route the session is empty:
#app.route(...)
def current():
print(session.keys(), session.values) # Empty !
I have installed Flask Session and set the config to:
'SECRET_KEY': b'...',
'SESSION_TYPE': 'filesystem', # Memcache, null and redis
'SESSION_PERMANENT': False, # True
And then started the Flask application and it not work. I have also try to set session.modified = True after I add some new value to session and still not work.
I have read lots of threads on Stack Over Flow, Reddit, etc; and nothing worked. Tips please ?

TL;DR, enable CORS and credentials support on the back end, and use credentials in the front end code when issuing requests.
I recently ran into a similar issue where I was developing a front end and a back end in separate apps. I noticed that each time I issued a request from the front end client, it would create a new session for each request, which would rapidly bloat the session storage on the back end and made user tracking difficult if not impossible.
I'm assuming that you're Javascript app and Flask app are running separately (i.e., the javascript is not on a template being served by the Flask app and hence the js requests are coming from a different origin).
Suppose we have a simple app with Flask-Session enabled running on port 5000:
from flask import Flask, session
from flask_session import Session
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
#app.route('/foo')
def foo():
return session.sid
#app.route('/bar')
def bar():
return session.sid
Now if we run the app if we navigate to either route on a browser(e.g., http://localhost:5000/foo), we would get the same session id. If you open another tab, open the developer tools and issue the following command in the console, you'd get a cors error:
// Using fetch, you can use jquery or axios
fetch("http://localhost:5000/foo").then(response => {
return response.text()
}).then(data => {
console.log(data)
})
You can fix this easily by installing Flask-CORS and wrapping your app in the CORS class:
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)
#app.route('/foo')
def foo():
return session.sid
#app.route('/bar')
def bar():
return session.sid
Now if you run the javascript fetch function above, it prints out a different session id each time the request is invoked, even for the same route. That's because Flask can't track the session unless you're issuing the requests from the same origin or unless you provide some way for flask to identify the session. You can do this from your JS by allowing credentials to be passed:
fetch("http://localhost:5000/foo",
{ credentials: 'include' }).then(response => {
return response.text()
}).then(data => {
console.log(data)
})
However, you will get another CORS error regarding Access-Control-Allow-Credentials. You can fix this in you're Flask app by import the cross_origin decorator, wrapping your routes in the decorator and passing supports_credentials=True to the decorator. The flask code would look something like this:
from flask import Flask, session
from flask_session import Session
from flask_cors import CORS, cross_origin
app = Flask(__name__)
SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)
#app.route('/foo')
#cross_origin(supports_credentials=True)
def foo():
return session.sid
#app.route('/bar')
#cross_origin(supports_credentials=True)
def bar():
return session.sid
Now flask can track the session by the requester (in this case, the browser running the Javascript app).

I had the same problem using classic post request in html. The session, which was still storing values in previous route, would empty itself after my post request.
I solved this using:
app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE=True)
I am sharing this in case others are facing the same issue.

Related

Can I use Flask Restful alongside an existing Flask App?

I have been tasked with working on an existing Flask project (Flask with Templates/Jinja2 style monolith application). I have to add new features to this app and I'm also intending to re-design the app so it becomes a more micro-services based architecure (i.e. initially Flask-restful based backend with React based front-end). Can I just use Flask-restful by just wrapping the existing app and start creating the new endpoints using Resource?
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
Are there any specific caveats/gotcha's I need to worry about?
Let's try it and see what happens. We start with a basic Flask app:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index():
return "This is index\n"
#app.route("/endpoint1")
def endpoint1():
return "This is endpoint1\n"
This works and we can request the / and /endpoint1 endpoints and get the expected response:
$ curl localhost:5000
This is index
$ curl localhost:5000/endpoint1
This is endpoint1
Let's see if we can mash a flask_restful managed endpoint in there without disrupting the existing functionality:
from flask import Flask, make_response
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Widgets(Resource):
def get(self):
return make_response('Yes we have no widgets today\n')
api.add_resource(Widgets, '/widgets')
#app.route("/")
def index():
return "This is index\n"
#app.route("/endpoint1")
def endpoint1():
return "This is endpoint1\n"
Are our original routes still active?
$ curl localhost:5000
This is index
$ curl localhost:5000/endpoint1
This is endpoint1
How about the new one?
$ curl localhost:5000/widgets
Yes we have no widgets today
It looks like the answer is "yes"!

Prevent shared session in flask subdomains

I have a flask running at http://base1.homologation.test.
I also have another flask instance on same server running at http://base2.homologation.test
they are two different systems, operating independently.
Whenever I log in to the first one, I can check the session data referring to it in the second, causing both application and security errors.
How can I prevent the sessions from being shared between the apps, so that each one has its own?
root views.py
from flask import *
from . import app
app.secret_key = 'random string'
#app.route('/', subdomain='base1')
def base1():
pass
#app.route('/', subdomain='base2')
def base2():
pass
#app.route('/')
def hqq():
return render_template('test.html')
root init.py
from flask import *
from .base1 import base1
from .base2 import base2
app = Flask(__name__)
app.register_blueprint(base1, subdomain='base1')
app.register_blueprint(base2, subdomain='base2')
import E_Commerce.views
PS: I am using the default session (session['']).

Flask route at / returns 404 when used with Flask-Restplus

I have a Flask app which has a Flask-RestPlus API as well as a "/" route. When I try to access "/" however, I get a 404. If I remove the Flask-RestPlus extension, the route works. How do I make both parts work together?
from flask import Flask
from flask_restplus import Api
app = Flask(__name__)
api = Api(app, doc="/doc/") # Removing this makes / work
#app.route("/")
def index():
return "foobar"
This is an open issue in Flask-RestPlus. As described in this comment on that issue, changing the order of the route and Api solves the issue.
from flask import Flask
from flask_restplus import Api
app = Flask(__name__)
#app.route("/")
def index():
return "foobar"
api = Api(app, doc="/doc/")
flask-restplus defines a different way of assigning routes according to their docs:
#api.route('/')
class Home(Resource):
def get(self):
return {'hello': 'world'}
Notice that the api variable is used instead of the app. Moreover, a class is used although I am not 100% sure it is required.

Prevent Flask from ever sending Set-Cookie?

Can I prevent Flask framework from ever sending a Set-Cookie header?
I'm using a variety of blueprints that use the session cookie. I'm wondering if there is a way to tell the framework to simply never try to set cookies. I'd like to not have to prepare each individual response using suggestions like this or using app.after_request.
You can create custom session interface and override should_set_cookie method
from flask import Flask
from flask.sessions import SecureCookieSessionInterface, SessionMixin
class CustomSessionInterface(SecureCookieSessionInterface):
def should_set_cookie(self, app: "Flask", session: SessionMixin) -> bool:
return False
app = Flask(__name__)
app.session_interface = CustomSessionInterface()

the session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret. Flask/Heroku

The flask app can login and register all fine on localhost. But this becomes an issue when i push it to heroku. It shows the above mentioned error. Here's the app.py code
from flask import Flask, render_template, request, redirect, jsonify, url_for, flash
from sqlalchemy import create_engine, asc, desc
from sqlalchemy.orm import sessionmaker
from database_setup import Base, User, BlogPost
from flask import session as login_session
import random
import string
from wtforms import Form, BooleanField, TextField, PasswordField, validators
from passlib.hash import sha256_crypt
app = Flask(__name__)
#Connecting to database
engine = create_engine('sqlite:///travellerdata.db')
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
And ends with...
if __name__ == "__main__":
app.secret_key = 'some secret key'
app.debug = True
app.run()
I have the same issue when I use flask-login to generate a session ID, it works fine when I directly run it but will output error when I use HTTP server. The original code is like:
if __name__ == "__main__":
app.secret_key = os.urandom(24)
app.run()
Then I moved app.secret_key = os.urandom(24) out of __name__ and put it under app = Flask(__name__) like this:
app = Flask(__name__)
app.secret_key = os.urandom(24)
login_manager = flask_login.LoginManager()
login_manager.init_app(app)
And it works fine now.
It's likely that when your HTTP server is loading your application, __name__ is not equal to 'main'. Try moving the line app.secret_key = 'some secret key' outside the if block.
It's not a good idea to put your secret key in source code because if anyone gets it they can malevolently gain access to your system. Try storing it in a file in the application's instance directory (snippet here) or putting it in an environment variable (explanation here).
The exception is raised by the NullSessionInterface session implementation, which is the default session type when you use Flask-Session. That's because you don't ever actually give the SESSION_TYPE configuration to Flask; it is not enough to set it as a global in your module.
This default doesn't make much sense with Flask 0.10; it may have made sense with Flask 0.8 or 0.9, but the current version is used as an error signal. In your case it gives you the wrong error message now.
Set the SESSION_TYPE configuration option to something else. Pick one of redis, memcached, filesystem or mongodb.
Setting it to filesystem is easiest; there is enough default configuration there to have that work without additional dependencies:
if __name__ == "__main__":
app.secret_key = 'super secret key'
app.config['SESSION_TYPE'] = 'filesystem'
sess.init_app(app)
app.debug = True
app.run()
I read this on random website after tried a lot a lot of solution but nothing worked the solution was very simple for me i just put
app.secret_key = 'super secret key'
after app = Flask(name) directly not in the bottom of the file.

Categories