Search code examples
pythonauthenticationflasksession-stateflask-login

Session Persistence Issue with Flask and Frontend: Session Lost After Successful Login


I'm developing a web application using Flask for the backend and Angular for the frontend. My frontend runs on http://localhost:4200, and my backend runs on http://127.0.0.1:5000. I've implemented a login system using Flask-Login, but I'm encountering an issue where the session does not persist after a successful login.

Issue Description: After a successful login, the backend sets a session cookie in the browser. However, when I try to access protected routes (e.g., http://127.0.0.1:5000/api/player/info), the server responds with {"is_authenticated": false}, indicating that the session is not recognized.

Code Samples:

__init__.py:

import os
from flask import Flask
from flask_cors import CORS
from flask_login import LoginManager
from flask_session import Session

from .database import db, migrate
from .models import Player


# Initialize app for Flask-Login
login_manager = LoginManager()
login_manager.login_view = 'auth.login'


@login_manager.user_loader
def load_user(user_id):
    return Player.query.get(int(user_id))


def create_app():
    app = Flask(__name__)
    env_config = os.getenv("APP_SETTINGS", "config.DevelopmentConfig")
    app.config.from_object(env_config)

    # Initialize app for Flask-Session
    Session(app)

    # Handle CORS (Cross-Origin Resource Sharing)
    CORS(app, supports_credentials=True)

    # Initialize app for SQLAlchemy
    db.init_app(app)

    # Initialize app for Flask-Login
    login_manager.init_app(app)

    # Initialize app for Flask-Migrate
    migrate.init_app(app, db)

    # Register blueprints
    from .blueprints import auth_bp, player_bp
    app.register_blueprint(auth_bp, url_prefix="/api/auth")
    app.register_blueprint(player_bp, url_prefix="/api/player")
  
    return app

Flask Login Route:

@auth_bp.route('/login', methods=['POST'])
def login():
    # ... [authentication logic] ...
    login_user(user, remember=remember)
    return jsonify({"message": "Logged in successfully"}), 200

Flask Route to Fetch Player Info:

@player_bp.route('/info', methods=['GET'])
def get_player_info():
    if current_user.is_authenticated:
        return {"is_authenticated": True, "name": current_user.name}
    return {"is_authenticated": False}

Angular Service for Login:

login(userData: { username: string; password: string; remember: boolean }): Observable<any> {
    const url = `127.0.0.1:5000/api/auth/login`;
    return this.http.post(url, userData, { withCredentials: true });
}

Steps Taken:

  1. The login function authenticates the user and calls login_user(user, remember=remember).
  2. CORS is configured with supports_credentials=True to handle cross-origin requests.
  3. The Angular HttpClient is configured with { withCredentials: true } to ensure that the session cookie is sent with requests.
  4. I verified that the session cookie is set in the browser after login.
  5. I checked the request headers for subsequent requests, and the session cookie is being sent to the server.
  6. I tried using Flask's default session management and Flask-Session with Redis, but the issue persists.
  7. To further isolate the issue, I created a basic HTML and JavaScript page and hosted it on a different port, similar to my Angular setup. This minimal setup was aimed at interacting with the Flask backend. Despite simplifying the frontend environment, I encountered the same session persistence problem: the session established after login does not seem to be recognized by subsequent requests, suggesting that the issue might not be Angular-specific but potentially related to session management or handling of cross-origin requests across different ports.

Expected Behavior: Upon successful login, I anticipate that a subsequent GET request to http://127.0.0.1:5000/api/player/info would yield a JSON response like this:

{
  "is_authenticated": true,
  "name": "foo"
}

This would indicate that the session is persisting correctly and that the server is acknowledging the authenticated state of the user, alongside providing associated user information.

I would appreciate any insights or suggestions to resolve this issue. Thank you!


Solution

  • For those facing the same issue, I solved this issue by:

    1. Adding the following to my __init__.py:
     app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE=True)
    
    1. Making sure that my javascript requests contain:
    credentials: 'include' 
    

    More info here: Flask session don't persist data