6
votes

I have an Angular app that needs to call a Flask server that use sessions to store information between requests.

I also have an older JS app that called the same server using XMLHttpRequest, that I am replacing with the new Angular app.

The trouble is that when the old app was making a request, session cookies were working as expected but now with the angular app it does not.

All interactions are done over localhost. The Flask server is accessible from localhost:5000, and the Angular app from localhost:4200.

The old app was doing request like this:

var xhttp = new XMLHttpRequest();
xhttp.open("GET", "http://localhost:5000/api/getAll", true);
xhttp.withCredentials = true;
xhttp.send();

The Angular app is doing like so:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, } from '@angular/common/http';
import { Observable } from 'rxjs';

const httpOptions = {
  withCredentials: true,
  headers: new HttpHeaders({ 
    'Content-Type': 'application/json',
    'charset': 'UTF-8',

    })
};


@Injectable()
export class ServerService {
  url = "http://localhost:5000/api/"

  constructor(private http:HttpClient) { }

  getAll(): Observable<string>{
    return this.http.get<string>(this.url + 'getAll', httpOptions);
  }

  login (username: string): Observable<string> {
    return this.http.post<string>(this.url + 'login', JSON.stringify({"username": username}), httpOptions)
  }

}

And the Flask server:

from flask import Flask, session, request, jsonify
from flask_cors import CORS
import os
import Person
import multiprocessing as mp
import json
import Insurance
import datetime
import Functions
import missingVal


app = Flask(__name__)
CORS(app, supports_credentials=True)

# set the secret key. keep this really secret:
# The value come from calling os.urandom(24)
# See https://stackoverflow.com/a/18709356/3729797 for more information
# app.secret_key = b'fL\xabV\x85\x11\x90\x81\x84\xe0\xa7\xf1\xc7\xd5\xf6\xec\x8f\xd1\xc0\xa4\xee)z\xf0'
app.config['SECRET_KEY'] = b'fL\xabV\x85\x11\x90\x81\x84\xe0\xa7\xf1\xc7\xd5\xf6\xec\x8f\xd1\xc0\xa4\xee)z\xf0'




@app.route('/api/getAll')
def getAll():
    response = jsonify()
    if 'username' in session:
        user = users[session['username']]
        # some more logic here
        response = jsonify({'username': session['username']})

    return response

# login and account creation    
@app.route('/api/login', methods=['POST'])
def login():
    response = jsonify()
    if users.get(request.json.get('username')) is not None:
        session['username'] = request.json.get('username')
        # some more logic here
        response = jsonify({'username': session['username']})

    response.headers.add('Access-Control-Allow-Methods',
                         'GET, POST, OPTIONS, PUT, PATCH, DELETE')
    response.headers.add('Access-Control-Allow-Headers',
                         "Origin, X-Requested-With, Content-Type, Accept, x-auth")
    return response


if __name__ == '__main__':
    # some more logic here
    app.run(host='localhost', threaded=True

The problem is that when I log in, it push information into the session, and when I do another request, I check if that information is in the session but it does not.

I found a lot of other related question on StackOverflow:

  • this one has to do with setting the secret_key multiple times, which is not my problem.
  • this one talk about static versus dynamic configuration in init but I don't think it has anything to do with my problem? Tell me if I'm wrong.
  • this one and this other one had trouble because their payload inside the cookie was too big, only 4096bytes or less are allowed it seems. But I only put a username that is a few letters into my cookie so I don't believe it is my problem.
  • this one I thought was related to my problem because it deals with localhost, but it turns out that it was because OP was mixing requests on 127.0.0.1 and localhost and cookies are processed separately by flask apparently. I do all my request on localhost so not related I believe.

I'm a bit lost right now, there is probably something very obvious I am missing but can't figure it out, any suggestion appreciated

1

1 Answers

3
votes

I got it working by adding

response.headers.add('Access-Control-Allow-Headers',
                         "Origin, X-Requested-With, Content-Type, Accept, x-auth")

in the Flask server before sending back all requests.

For example

@app.route('/api/doSomething', methods=['POST'])
def doSomething():
    response = jsonify()
    if 'username' in session:
        # some logic here
        response = jsonify(someData)

    # here is the line I added
    response.headers.add('Access-Control-Allow-Headers',
                         "Origin, X-Requested-With, Content-Type, Accept, x-auth")
    return response

Apparently it is needed when doing CORS, some good informations on MDN