so

Cookie changes on redirects

Volume 7, Issue 13; 27 Jan 2023

TIL: The NodeJS express framework changes the login session cookie on redirect so, if you aren’t careful, Python will not successfully manage the state.

This must be a relatively recent change to how sessions work in Express. I spent a long time digging around in JS last night trying to work out what had changed before careful inspection with Charles led me to the actual problem.

The former workflow was:

  1. Attempt to connect to site
  2. Get redirected to login page with a session cookie
  3. Post the login credentials
  4. If the credentials are accepted, get redirected back to the home page
  5. Proceed with the session cookie

The new workflow is:

  1. Attempt to connect to site
  2. Get redirected to login page with a session cookie
  3. Post the login credentials
  4. If the credentials are accepted, get redirected back to the home page with a new session cookie
  5. Proceed with the new session cookie

What you have to remember is that the Python requests API will follow redirects automatically. That means you won’t see the updated cookie in the 200 response that comes back from the redirect because you’ve missed it.

Instead of

resp = requests.post(login, data=data, verify=self.verify,
                     cookies=self.cookies)

if resp.status_code != 200:
    raise RuntimeError(f"Login failed ({resp.status_code}): {resp.text}")

you have to do something more like this:

resp = requests.post(login, data=data, verify=self.verify,
    allow_redirects=False, cookies=self.cookies)

if resp.status_code == 302:
    if (len(resp.cookies) > 0):
        self.cookies = resp.cookies;

    redirect = resp.headers["location"];
    if "://" not in redirect:
        redirect = parsed.scheme + "://" + parsed.netloc + resp.headers["location"]
    
    resp = requests.get(redirect, verify=self.verify,
        cookies=self.cookies)

if resp.status_code != 200:
    raise RuntimeError(f"Login failed ({resp.status_code}): {resp.text}")

(The bit in the middle about parsed.scheme and parsed.netloc are from an earlier assignment: parsed = urlparse(self.uri).)

I suppose it’s possible that the cookie change could be avoided by changing the way authentication is done on the server, but this was way easier.

#NodeJS #Python #TIL