Search code examples
pythonflaskfetch-apiflask-login

Flask login_required cause 401 error when using js fetch (Blueprints)


I separate my backend and frontend. the backend is write with flask and the front with simple js with fetch requests to interact with the backend.

The authentification is done in backend with flask login, I decorated some endpoints with @login_required.

The problem is I logged correctly with http code 200 but when i want to request some enpoints with js, my @login_required cause 401 unauthorized error. Noted that I separate my routes in differents blueprints.

I checked and see that after login I have a session id which is different from the one I'm getting in fund_request_bp blueprint where my request is done. I also remarked that I have the same session id when I call all my endpoints in the fund_request_bp blueprint.

login code

from config import app, db, login_manager, default_password
from models import User
from flask import Blueprint, request, jsonify, render_template, redirect, url_for, flash, session
from flask_login import login_user, logout_user, login_required, current_user

user_bp = Blueprint("user", __name__)

@user_bp.route('/login', methods=['POST'])
def login():
    data = request.form

    user = User.query.filter_by(username=data.get('username')).first()

    if (user and user.check_password(data.get('password')) and data.get('password')==default_password):
        return jsonify({"message": "Redirect To Change Password !"}), 303
    elif (user and user.check_password(data.get('password'))):
        login_user(user)
        session['test'] = 'valuetest'
        print(session.sid)
        return jsonify({"message": "Login successfully"}), 200
    else:
        return jsonify({"error": "Invalid username or password."}), 404

other blueprint


fund_request_bp = Blueprint("fund_request", __name__, url_prefix="/fund_requests")

@fund_request_bp.route("/", methods=["GET"])
@login_required
def get_all_fund_request():
    fund_requests = FundRequest.query.filter_by(approval_level=current_user.user_level.level)

    if fund_requests.first() is None:
        return jsonify({"message": "No Funds request found."}), 200

    fund_requests_serialized = [fund_request.serialize() for fund_request in fund_requests]

    return jsonify(fund_requests_serialized), 200

js code

fetch(api_base+"/fund_requests", {
    credentials: 'include'
})
.then(response => response.json())
.then(data => {
    console.log(data)
})
.catch(error => {
    console.error("Error fetching data:", error);
});

Here is my Config

app = Flask(__name__)
app.config['SECRET_KEY'] = 'some_secret_key'
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_COOKIE_PATH'] = '/'
login_manager = LoginManager(app)
CORS(app, supports_credentials=True)
Session(app)

Ps: I used postman for tests and did not get any issue

I expect the request to get into the endpoint without being blocked by the @login_required decorator.


Solution

  • I find the solution, we need to add credentials: 'include' to every request done with fetch in js. I did not add it to the login request.

    fetch( '/login',{
              method: 'POST',
              body: data,
              credentials: 'include'
              },)
    .then(response=> {
                console.log(response.status);
            })
    .catch (err => {
            console.log(err.message);
          });