I don’t like cookies; they are stateful security-by-obscurity hacks for a fallen world. Still, they are a must-have for real web-applications. Does anyone have code snippets they’d be willing to share or links with instructions for how you use them effectively in Clojure?
We use them for some non-critical things almost as a cache, and we use them in a few places to record a preference (such as choice of locale) for non-logged-in visitors.
Wow – how do you manage user sessions?
We built an OAuth2 Server (so we have a World Singles Networks Identity Model) and we use access / refresh tokens, with the access token passed in each request. Most of the “session state” is held in the front end (a React.js SPA, using Local Storage as appropriate), but we also have some back end state held in a database. Our API is stateless and distributed (so a user session can bounce from server to server with no issues).
The front end initially posts to the Auth Server with app credentials. That redirects to the Login Server with a short-lived code. The user logs in (the Login app is a traditional SSR web app but passes a token from page to page rather than maintaining any server-side state). On successful login, the Login Server redirects back to the front end app with another short-lived code, which the app exchanges with the Auth Server in order to get an access / refresh token pair, which the front end then uses to interact with the API Server.
Periodically, the front end exchanges the refresh token with the Auth Server (again passing its app credentials) to get a new access / refresh token pair in order to keep the session going.
This is all standard OAuth2 stuff that you’d use with Facebook / Google / whatever.
On the back end, we use Redis as a TTL cache for some user presence information, and also as a pub/sub hub for tracking presence changes. That’s how we know whether a user is currently active. And then we store longer-term “session state” in MySQL if necessary, with periodic processes to purge “old” state.
(not= "Local Storage" Cookies)? And isn’t all SSO (Facebook, Google, whatever) stuff powered by cookies?
The front end maintains state however it wants – a mixture of cookies and/or LocalStorage – but the (opaque) access/refresh tokens are all the back end cares about.
I’ve found it useful to consider cookies as a migrate-able database. Migration is a handy way of dealing with the inevitable evolution of the structure of the data stored in the cookie. You can’t magically update every cookie simultaneously. When a cookie with the old schema appears simply dumping the entire value and replacing with a clean new “database” is too abrupt for many use cases. Migrations solve that problem nicely. We’ve found having the cookie’s value be an encrypted EDN map with a
:version attribute at the top works OK.
Upon successful decryption, the “database” is migrated, if necessary, to the latest version and re-written (encrypted).
The data you choose to store in a cookie needs to be carefully weighed against the security risks you are willing to tolerate. Even encrypted cookies are susceptible to replay and hijacking, so make sure such an attack does not compromise sensitive user data.
And, of course, cookies represent state and the less of that you have the better.
In my experience JWT or OAuth tokens are not a(n easy) replacement for good old session cookies. I was trying to leverage them in order to build a stateless auth layer but then faced issues with
- where to securely store them in the browser (cfr.
HttpOnlysession cookies and XSS vulnerabilities)
- plain and simple logout mechanics (problematic with JWT or any stateless token)
- the considerable engineering efforts required which, in my case, were just too much (we didn’t need SSO, for intance)
My current thinking is that OAuth2 can offer many extra features compared to plain session cookies, SSO and server-to-server authentication above others, but when it comes to managing web sessions I still think session cookies are still quite a valid option. I might even consider to go as far as using them even if OAuth2 is employed, exchanging the access token for a session cookie (or using the access token itself as such), just for the sake of XSS mitigation.
Some relevant content: https://medium.com/@yuliaoletskaya/can-jwt-be-used-for-sessions-4164d124fe23