skip to Main Content

I have a flask server running on http://127.0.0.1:5000 and a vuejs frontend running on http://localhost:8080 I have made the api and tested it with postman and everything works as expected:(

  • POST request to /login -> login successful -> perform actions a logged in user is allowed).

    But when I send the request from vuejs (using axios) then cookies dont seem to work

  • ( POST request to /login -> login successful -> cant perform actions allowed to logged in user (if ‘loggedin’ in session is False in flask) ).

Flask API code :

app = Flask(__name__)



SESSION_TYPE = 'redis'
app.config.from_object(__name__)
app.config.from_mapping(
    SECRET_KEY='dev'
)
app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE=True)
cross_origin(automatic_options=True)
app.config['CORS_HEADERS'] = 'Content-Type'
CORS(app, resources={r"/*": {"origins": "*"}},support_credentials=True)


## configure db
db = yaml.load(open('db.yaml'))
app.config['MYSQL_HOST'] = db['mysql_host']
app.config['MYSQL_USER'] = db['mysql_user']
app.config['MYSQL_PASSWORD'] = db['mysql_password']
app.config['MYSQL_DB'] = db['mysql_db']
mysql = MySQL(app)

## Homepage
@app.route('/index',methods=['GET'])
@cross_origin(supports_credentials=True,origin='http://localhost:8080/')
def index():
    if 'loggedin' in session:
        return jsonify({
            "msg":"user is logged in",
            "data":{
                "username":session['username'],
                "loggedin":True
            },
            "status":200
        })
    else:
        return jsonify({
            "msg":"user is not logged in",
            "data":{
                "username":None,
                "loggedin":False
            },
            "status":200
        })

## LOGIN 
@app.route('/login',methods=['GET','POST'])
@cross_origin(supports_credentials=True,origin='http://localhost:8080/')
def login():
    # print("initial check ",('loggedin' in session))
    if request.method == 'POST':
        req = request.get_json()
        username = req['username']
        password = req['password']
        cur = mysql.connection.cursor()
        if username == "" or password == "":
            return jsonify({
                'msg':'Username and password required',
                'status':401
            })

        user = cur.execute('SELECT * FROM user WHERE username =%s',(username,))
        userdetails = cur.fetchone()
        if user <=0 or not check_password_hash(userdetails[1],password):
            result = {
                'msg':'Incorrect username or password',
                'status':401
            }
            return jsonify(result)
        else:
            session.clear()
            session['username'] = userdetails[0]
            session['loggedin'] = True
            ## print("session username = ",session['username'])
            result = {
                'msg':"Successfully logged in",
                'status':200
            }
            print("inside login <loggedin> = ",('loggedin' in session))
            globallogin = True
            globalusername = userdetails[0]
            return jsonify(result)
            ## return redirect('/index')
    
    return jsonify({
        "msg":"get request at /login",
        "status":200
    }) 

Login.vue :

<template>
<div id = "login">
    <h1>Login page</h1>
    <label>Username</label>
    <input type="text" v-model="username">
    <label>Password</label>
    <input type="password" v-model="password">
    <button v-on:click="login()">Log in</button>
</div>
    
</template>

<script>
import axios from 'axios'
export default {
    data: function(){
        return{
            username:"",
            password:""
        }
    },
    methods:{
        resetform: function(){
            this.username = ""
            this.password = ""
            return
        },
        login: function(){
            const payload = {
                username:this.username,
                password:this.password
            }
            axios.post("http://127.0.0.1:5000/login",payload,{withCredentials: true})
            .then( (data) =>{
                console.log(data)
                if(data.data.status == 401){
                    alert(data.data.msg)
                    this.resetform()
                }
            }).catch( (err) => {
                console.log(err)
            })
        }
        
    },
    mounted() {
        axios.get("http://127.0.0.1:5000/login")
        .then((data)=>{
            console.log(data);
        })
    }
}
</script>

Index.vue

<template>
    <h1>Index page</h1>
</template>

<script>
import axios from 'axios'
export default {
    mounted(){
        axios.get('http://127.0.0.1:5000/index').then((data)=>{
            console.log(data)
        }).catch((err)=>{
            console.log(err);
        })
    }
}
</script>

When I login using postman I get response as successfully logged in and when I GET url/index using postman I get "user is logged in" in response.data but when I login using browser (chrome) from vuejs server I still get "successfully logged in" in response.data.msg but when I go to /index I get "user is not logged in".

Another thing that I noticed is that in postman after the login request there is a set-cookie header with the cookie id Set-Cookie = session=77e40d54-066c-48a7-9b2b-88f36d9a3b86; HttpOnly; Path=/ but when I console log the response from vuejs in the header field there is no set-cookie header (only application-type and content-length)

3

Answers


  1. Chosen as BEST ANSWER

    After finding no working solution I used JWT to solve this issue
    docs: https://flask-jwt-extended.readthedocs.io/en/stable/

    When client makes a request first time the flask server authenticates the client and if successfully authenticated it sends jwt token with the response. Client (vuejs) uses this token in subsequent requests to the server and each time the server verifies if the header contains the token


  2. I think you are missing {withCredentials: true} in your get call , but i could be wrong.

    Login or Signup to reply.
  3. I know this post is 1 year old, but I struggled so much with this that I want to share the solution that worked for me.

    In fact, the browser is preventing you from storing cookies received from other addresses than the client’s one. If you are careful enough, you can notice this error message

    It basically summarizes what I said above.

    THE SOLUTION is to make your client-side and backend have the same address, which is "localhost". So instead of querying 127.0.0.1:5000 with axios, just use localhost:5000.

    like this :

    axios.get("http://localhost:5000/login")
        .then((data)=>{
            console.log(data);
        })
    

    If you are using DJANGO, don’t forget to add "localhost" to your ALLOWED_HOSTS list in the settings.py file.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search