This page likely won't work without JavaScript enabled.Cognito with secure cookies

Cognito, API Gateway authorizers and secure cookies

I attempted to build an auth solution using Cognito and cookies.

The default option for implementing auth with Cognito in a web app is the aws-amplify library. It offers an easy JavaScript api for auth cases from sign up, through signing in with a social provider, to a global sign out.

aws-amplify uses localStorage for credential storage. I was not convinced that this was secure. auth0 in its guides clearly says not to store credentials in localStorage, linking to an OWASP cheatsheet that cautions agains putting sensitive data in localStorage.

The risk is that a malicious script which found its way onto the page could access and use the user's credentials. A Content-Security-Policy is recommended as protection agains cross-site scripting, so I made sure my project implemented a CSP. However, I still decided that cookies were the way to go.

To set and read cookies, I implemented a few auth methods in Lambda functions, including signUp, confirmAttribute, signIn, refreshToken and signOut. I switched my local development environment to SSL, in order to test secure cookies, which was a project in its own right.

I had a working auth flow, complete with simple front end forms. To try it out, I created a new API in API Gateway which I wanted to protect using auth credentials. Only authenticated users would have access to protected endpoints.

I created an Authorizer for the API. Authorizers can read request credentials from a few sources, including headers and query parameters. An authorizer, however, cannot access the request's cookies. This turned out to be a dead end. Even a Lambda function used as a custom authorizer does not receive cookies in the request forwarded by API Gateway.

I reevaluated my options. On the one hand: the safety of http-only cookies and CSRF tokens at the cost of risking a custom backend logic that communicates with Cognito. On the other: the convenience of an Amazon-maintained library at the risk that an npm package is hijacked and modified specifically to delete all user data in my web app.

Assuming that a malicious script was free to execute on the page, the only way to protect against forgery would be an http only cookie and a confirmation page after each form, protected with a CSRF token. It's a pattern I see in bank and government sites and I'm sure it offers the best possible protections. That level of security also requires audits and sign-offs for every line of code imported from npm.

I'll stick with a CSP and out-of-the box solutions that allow JavaScript to read security credentials. I'm only securing my shopping list after all.