Search code examples
reactjsflaskwsgisetcookieflask-session

Flask session is not able to create cookies (using set-cookie response headers) on react front end application


Problem

I'm trying to use server side session (saved on PSQL db) but they are not persisting in between the requests.

Description

I'm running my application locally and is of two parts.

  1. Backend running on MY_IP:2501
  2. Frontend running on MY_IP:3000

Now as per my understanding, Flask saves the session in the "session" table of PSQL (since we are storing server side sessions) and the ID from that particular row is sent to the client in the form of a response header i.e. "Set-Cookie".

Every thing described above is working, but when the React frontend (or browser) receives this header it doesn't creates a cookie out of it because of which the session id is not stored in the frontend and then the frontend is unable to send the same to the backend due to which it is not able to fetch the associated session data resulting in empty session every time.

:(

Stuff I've tried so far..

  1. Done allowing all type of headers while returning the response.

     `response.headers.add('Access-Control-Allow-Headers', "Origin, X-Requested-With, Content-Type, Accept, x-auth")`
    
  2. Done allowing the withCredentials header attribute from front end as well as backend.

  3. Removed HttpOnly parameters from the session using "SESSION_COOKIE_HTTPONLY" config property

  4. Done setting the "SESSION_COOKIE_DOMAIN" same as the front end

NOTE

  1. If I call my API via POSTMAN the session is persisting as the cookie is saved in POSTMAN.

  2. If I run the application on chrome --disable-web-security, then also it works.


Solution

  • Only configuration that is required:

    1. Send the request (REST / GraphQL) with the header withCredentials = true.
    2. Add Access-Control-Allow-Credentials = true headers from the backend.

    On Axios (Frontend REST API).

    import axios from 'axios';
    
    export const restApi = axios.create({
      baseURL: urlBuilder.REST,
      withCredentials: true
    });
    
    restApi.interceptors.request.use(
      function(config) {
        config.headers.withCredentials = true;   # Sending request with credentials
        return config;
      },
      function(err) {
        return Promise.reject(err);
      }
    );
    

    On Apollo (Frontend GraphQL)

    import {
      ApolloClient,
      ApolloLink
    } from 'apollo-boost';
    
    const authLink = new ApolloLink((operation, forward) => {
      operation.setContext({
        fetchOptions: {
          credentials: 'include' .         # Sending request with credentials
        }
      });
      return forward(operation);
    });
    

    On Python-Flask (Backend)

    @app.after_request
    def middleware_for_response(response):
        # Allowing the credentials in the response.
        response.headers.add('Access-Control-Allow-Credentials', 'true')
        return response