Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask: share sessions between domain.com and username.domain.com

I have a flask running at domain.com

I also have another flask instance on another server running at username.domain.com

Normally user logs in through domain.com

However, for paying users they are suppose to login at username.domain.com

Using flask, how can I make sure that sessions are shared between domain.com and username.domain.com while ensuring that they will only have access to the specifically matching username.domain.com ?

I am concerned about security here.

like image 310
I Love Python Avatar asked Jun 25 '14 01:06

I Love Python


People also ask

How to use session in flask?

To use session you must set the secret key first. The session object of the flask package is used to set and get session data. The session object works like a dictionary but it can also keep track modifications. When we use sessions the data is stored in the browser as a cookie. The cookie used to store session data is known session cookie.

What is permanent_session_lifetime in flask?

The permanent_session_lifetime is a datetime.timedelta attribute of Flask object, its default value is 31 days. We can change that by specifying a new value to permanent_session_lifetime attribute or by setting PERMANENT_SESSION_LIFETIME configuration key. Just like the request object, the session object is also available in the templates.

Can two applications share the same session-ID?

You are missing something: as long as those application share the same session state storage, the same session-id will represent the same session state. As session cookies in general are bound to domain on the client, you only need to pass session id when traversing the application boundaries.

Is it possible to share session state between servers?

Or you can use domain cookie if you're asking only and specifically about subdomain sites. Something like this Remember that cookies have size limits though. If this helps please take time to accept the solution. Thank you. Please Sign up or sign in to vote. If you have IIS infrastructure, you can share session state between servers.


2 Answers

EDIT: Later, after reading your full question I noticed the original answer is not what you're looking for.

I've left the original at the bottom of this answer for Googlers, but the revised version is below.

Cookies are automatically sent to subdomains on a domain (in most modern browsers the domain name must contain a period (indicating a TLD) for this behavior to occur). The authentication will need to happen as a pre-processor, and your session will need to be managed from a centralised source. Let's walk through it.

To confirm, I'll proceed assuming (from what you've told me) your setup is as follows:

  • SERVER 1:
    • Flask app for domain.com
  • SERVER 2:
    • Flask app for user profiles at username.domain.com

A problem that first must be overcome is storing the sessions in a location that is accessible to both servers. Since by default sessions are stored on disk (and both servers obviously don't share the same hard drive), we'll need to do some modifications to both the existing setup and the new Flask app for user profiles.

Step one is to choose where to store your sessions, a database powered by a DBMS such as MySQL, Postgres, etc. is a common choice, but people also often choose to put them somewhere more ephemeral such as Memcachd or Redis for example.

The short version for choosing between these two starkly different systems breaks down to the following:

Database

  • Databases are readily available
  • It's likely you already have a database implemented
  • Developers usually have a pre-existing knowledge of their chosen database

Memory (Redis/Memchachd/etc.)

  • Considerably faster
  • Systems often offer basic self-management of data
  • Doesn't incur extra load on existing database

You can find some examples database sessions in flask here and here.

While Redis would be more difficult to setup depending on each users level of experience, it would be the option I recommend. You can see an example of doing this here.

The rest I think is covered in the original answer, part of which demonstrates the matching of username to database record (the larger code block).

Old solution for a single Flask app

Firstly, you'll have to setup Flask to handle subdomains, this is as easy as specifying a new variable name in your config file. For example, if your domain was example.com you would append the following to your Flask configuration.

SERVER_NAME = "example.com"

You can read more about this option here.

Something quick here to note is that this will be extremely difficult (if not impossible) to test if you're just working off of localhost. As mentioned above, browsers often won't bother to send cookies to subdomains of a domain without dots in the name (a TLD). Localhost also isn't set up to allow subdomains by default in many operating systems. There are ways to do this like defining your own DNS entries that you can look into (/etc/hosts on *UNIX, %system32%/etc/hosts on Windows).

Once you've got your config ready, you'll need to define a Blueprint for a subdomain wildard.

This is done pretty easily:

from flask import Blueprint
from flask.ext.login import current_user

# Create our Blueprint
deep_blue = Blueprint("subdomain_routes", __name__, subdomain="<username>")

# Define our route
@deep_blue.route('/')
def user_index(username):

    if not current_user.is_authenticated():
        # The user needs to log in
        return "Please log in"
    elif username != current_user.username:
        # This is not the correct user.
        return "Unauthorized"

    # It's the right user!
    return "Welcome back!"

The trick here is to make sure the __repr__ for your user object includes a username key. For eg...

class User(db.Model):

    username = db.Column(db.String)


    def __repr__(self):
       return "<User {self.id}, username={self.username}>".format(self=self)

Something to note though is the problem that arises when a username contains special characters (a space, @, ?, etc.) that don't work in a URL. For this you'll need to either enforce restrictions on the username, or properly escape the name first and unescape it when validating it.

If you've got any questions or requests, please ask. Did this during my coffee break so it was a bit rushed.

like image 86
pmccallum Avatar answered Oct 18 '22 03:10

pmccallum


You can do this with the builtin Flask sessions, which are cookie-based client-side sessions. To allow users to login to multiple subdomains in '.domain.com', you need only to specify

 app.config['SESSION_COOKIE_DOMAIN'] = '.domain.com'

and the client's browser will have a session cookie that allows him to login to every Flask instance that is at 'domain.com'. This only works if every instance of Flask has the same app.secret_key

For more information, also see Same Flask login session across two applications

like image 38
arotman Avatar answered Oct 18 '22 04:10

arotman