Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Watch out for setCookie and clearCookie opts, as clearCookie mutates opts instance #165

Open
juhofriman opened this issue Nov 26, 2020 · 0 comments

Comments

@juhofriman
Copy link

juhofriman commented Nov 26, 2020

Hi!

Lambda-api is a great package and has been really helpful in our one single backend lambda architecture 🚀

Today, I faced a really hard to debug issue and I though passing the information here if it helps anyone else. I was running our app with SAM CLI and everything worked like a charm, but when I deployed to AWS lambda, it worked in really weird way.

The problem was that I had somewhat the following structure:

const cookieOptions: CookieOptions = {
  sameSite: 'Lax',
  secure: true,
  httpOnly: true,
}

// And pseudo authentication

api.post('/login', async (req,res) => {
  // Do login stuff
  res.setCookie('authcookie', sessionId, cookieOpts).json({ message: "Authenticated" })
})

api.post('/logout', async (req,res) => {
  // Do logout stuff
  res.clearCookie('authcookie', cookieOpts).json({ message: "Logged out" })
})

It worked locally like a charm. But when it was deployed to AWS Lambda, it worked like this:

  1. Login - OK you get a cookie
  2. Logout - OK cookie gets evicted
  3. Login - FAILS and no cookie is set
  4. After some time, it starts to work again, for once 😂

After some weird debugging I found out that the third call gets correct cookie, but with expiration set to -1, so the browser thinks that yes, unset the cookie.

Obvious reason for this is that response.clearCookie call mutates the given opts instance:

lambda-api/lib/response.js

Lines 221 to 224 in 0b753d8

clearCookie(name,opts={}) {
let options = Object.assign(opts, { expires: new Date(1), maxAge: -1000 })
return this.cookie(name,'',options)
}

After the first response.clearCookie call my opts instance was mutated to contain expiration: -1 field and calls to response.setCookie after that naturally included the expiration.

The reason why it works after some time in AWS lambda is that runtime spins up a new sandbox and then it works again, for once 😄, because opts instance is not mutated and no one has logged out. Locally SAM CLI fires a whole new sandbox for each request and thus it worked locally with no issues.

You can easily work around this for example by wrapping opts in function:

const cookieOptions = (): CookieOptions => ({
  sameSite: 'Lax',
  secure: true,
  httpOnly: true,
})

It surely took me some time to figure out what is going on 😄 I don't think this is mentioned in documentation. I think I can work out a PR for this if this is something that should be fixed - in code or with documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant