Launch HN: SuperTokens (YC S20) – Securely manage session tokens
We started SuperTokens 1.5 years ago when we were building a consumer app and wanted our users to be logged in for a long time in a secure way. When it came to managing user sessions, there was a lot of ambiguity. We read many forums (Reddit, Stackoverflow) and blogs, and found that developers were arguing about best practices, such as using local storage vs cookies, implementing JWTs, etc. We had to do a lot of the first principles thinking ourselves to understand the tradeoffs. Around the same time, Facebook, Docker, Gitlab, Youtube, Uber were in the news for session vulnerabilities.
Stealing a user’s session allows you to access their account as if you had their username and password. Hence being able to mitigate against this is important. We’ve audited companies and found large session vulnerabilities that they were not aware of. For a YC company, we were able to pull information on users that we shouldn’t have had access to.
Through our research, we built something internally and decided to write a blog post [1] explaining how our system works. While SuperTokens is not currently open source, you can see the original codebase on Github [2].
Building a good solution for sessions requires a lot of specialised knowledge and time that could otherwise be spent on building your core business logic. Detecting session theft reliably is difficult. There are multiple race conditions, edge cases and network issues that need to be thought about. In fact, one of our libraries that solves a difficult race condition has 100K downloads / week and is even used by Auth0 [3]
SuperToken mitigates against all session attacks (XSS, CSRF, etc) by implementing best practices. For a full list of types of attacks with real life examples please see [4]. However, it is not possible to mitigate against all attacks (for eg: social engineering) and hence, SuperTokens is also able to detect session theft. We use rotating refresh tokens as per the official OAuth specifications in RFC 6819 [5]. Auth0 has also started offering this, but due to their setup, they cannot use httpOnly cookies to store these tokens and this goes against popular compliance recommendations.
Besides security, SuperTokens also offers improved API performance and developer convenience. For clustered and distributed environments, session verification for each API takes < 1 millisecond. You can get a user’s ID and access role without any database lookup. SuperTokens can be implemented in 15 minutes, provides a simple API and has clear documentation. We abstract away complexities of token management by providing frontend and backend SDKs.
In the coming months we plan to offer Access Control, Internal Auth between services and for internal tools (i.e. recent Twitter hack was through unauthorized access to an internal tool), and more! We're still experimenting with pricing, so you won't find this on our website, but we'd love to hear your thoughts about it.
Thank you for reading! We’d love to hear what this community specifically has to say and if you have any experience dealing with this. We’d appreciate any feedback!
----------
Footnotes:
[1] - Blog post: https://medium.com/hackernoon/all-you-need-to-know-about-use...
[2] - Github: https://github.com/supertokens/supertokens-core
[3] - Library used by Auth0: https://www.npmjs.com/p...
61 comments
[ 2.3 ms ] story [ 114 ms ] threadAlso, maybe it's just me, but your landing page is very slow and laggy, and my browser hung a bit while navigating around.
About compliance & code audits, those are being planned. We will have code auditing done in a few weeks from now. But yea, I understand your point. Thanks!
Might want to update your Twitter, then?
@supertokensio The most secure solution for user session management... We're open source and easy to implement.
Also, for now, we have removed that claim from our Twitter.
It's neither the old open source version of supertokens, which is deprecated, or the new version of supertokens, but is in between.
Generate a secret, hash it, and store it in your database. Set the secret as a cookie in the client. On every request, hash the cookie value on your server and compare it to your DB values.
It seems like very little effort to implement this yourself in a way that doesn't involve completely trusting a different company.
As such, for long lived sessions, just having one token makes that the weakest link in that user's security. That's why we believe that this is a problem worth solving = minimising security risk.
The method you suggested is one that you understand and can build. A lot of developers do not know much about session security, but still want security.
Thanks for your feedback though. It's true that not all apps will want this level of security. We understand that.
Can you help me understand the specific attacks you're trying to mitigate that aren't already solved by a combination of best practices implemented by current engineering frameworks (session management across most fairly mature tech stacks) and browser controls (e.g. samesite cookies)?
-> Short lived sessions:
A lot of the guidelines (OWASP, NIST, industry compliances) recommend having short inactivity timeouts, and "in session", frequent reauths. Those have clear UX problems, but for apps that are OK with those problems, implementing such mechanisms is good enough, security wise! Most existing libraries easily allow you to build inactive timeouts, but building the frequent "in session" reauth, can be tricky: detecting when last auth happened, saving state of an app between reauths & regenerating session tokens after reauth. Due to these issues, sites end up implementing sessions from scratch and mostly always make some mistake. For example, I have seen banks store session tokens in the page HTML as opposed to HttpOnly cookies. One of our aim is to make it very simple to implement all these best practices recommended by OWASP, NIST, and industry compliances.
-> Long lived sessions:
For all other apps that want to keep their users logged in for longer, frameworks only enable the use of one long lived session token (alive for weeks or months). In this case, if that token is compromised, the user's account is compromised for a long time. Theft of token is possible in multiple ways, even if using httpOnly cookies: https://supertokens.io/pdf/attackshomepagev2
For some people, this risk matters. For them, they want to achieve long lived sessions + reduce the risks of theft. For them, using the existing framework solution is not good enough.
-> Functionality:
There are a lot of functionality that can be required on top of sessions:
- Syncing session data across devices
- Getting all active sessions of a user
- Setting different inactivity timeouts based on a user's role
- Revoking access to a specific device
- Logging in as a user (for support team)
Most of these and perhaps more are required for "serious" apps. Most frameworks do not allow to easily implement all of the above. As result, devs implement their own session solution, and make mistakes.
-> Other considerations:
For many devs, JWT is the goto for sessions (free scalability). Since most frameworks do not choose JWTs for sessions (in their inbuilt solution), devs choose to use something else and make mistakes like storing the JWTs in localstorage.
Incorrectly configuring sessions in these frameworks can also cause issues. For example, during development, secure attribute for cookies is usually set to false. Sometimes, devs forget to set them to true for production use. Another example is that during development, your API is on api.example.com, but your site is on localhost. For this to work, you set sameSite to none, and forget to switch it to lax for production. SuperTokens aims to be very opinionated in order to prevent such mistakes (...catching these errors is not yet implemented though, but soon).
-> Conclusion:
Overall, the in built sessions in the frameworks are good for many apps. However, for those "serious" or complex apps, people end up building something custom (and that's a lot of companies ~ 50% of our YC batch built a custom solution or used JWTs despite of inbuilt sessions in their framework). Our solution is for such people.
Is that a fair summary?
That said, considering the standard guidance around session management is "don't do it yourself," then by delegating to you, your customers also distribute that risk to you and gain some amount of indemnity as a result. So using SuperTokens would be a valid risk management strategy provided firms are:
1. fine with what's essentially indefinite vendor lock-in (at least until they ditch the software platform they've written that relies on SuperTokens), and
2. doing their diligence around your security controls.
And if they've met those conditions and feel that paid session management gives them extra UX cases that they don't have available to them for building out their solution, then more power to them.
The only implicit guidance in all of this that I'll make explicit is to make sure you're investing in the security of your platform considering it's the product you're selling. Many of your customers who would consider buying into this service would do so knowing that it essentially comes with some amount of indemnification regardless of whether or not you disclaim it.
Final thought: it'll help you a lot if you clearly define a Shared Responsibility Model that outlines the security responsibilities SuperTokens will own v. the security responsibilities the implementing customer will own. What'll help even further is if you can then cement your Shared Responsibility Model and prove the controls you claim to have with e.g. a SOC2 type 2 that defines Complementary User Entity Controls.
There's a market for what you're offering, but you'll have to be strategic about capitalizing on it and not potentially becoming a victim of your own success as you acquire customers who themselves will be the targets of attacks- ergo attacks against your platform.
> Storing only the hased versions of session tokens
But I'm glad the company offers a self-hosted version rather than being forced to rely on their managed service (that was the first thing I looked at). I haven't dug into it at all and am taking at face value that their self-hosted daemon doesn't have any required real-time connections to their systems, but that would be a deal killer as well.
Are you talking about OAuth2 tokens (i.e. https://tools.ietf.org/html/rfc6819#section-5.2.2.3), or are you talking about browser cookies?
In both cases, rotation strikes me as being of limited (though nonzero) value. While rotation (and invalidation of the previous token) can be used to prevent long-lived concurrent use of cloned tokens, there's a good chance an attacker can ensure that they are the ones who get the "new" token.
As a result, the user--the legitimate OAuth client or browser--would be left with the now-invalidated token, and will be logged out. The most likely result of which--depending on application design choices--is that the user simply logs in again! You now have two sessions, one of which is solely owned by an attacker, and one of which is solely owned by a user!
(There are cases where this is still valuable: if you enforce "only one session globally" per user, for example, or if you use the presentation of an "invalidated" token as indicative of theft. But both are application design choices that will commonly be inappropriate.)
At the extreme, of course, if your threat model is local malware, UXSS, etc, an attacker can just do a "person in the browser" attack, in which no token copying happens.
I'm not sure why I'm bothering to write all of this. Call it free consulting? ;)
My point is really that the threat model needs to be clearly stated and, for some threat models (including some which are featured in case studies on your website), this approach may be largely ineffective.
What about cookie configuration (secure, httpOnly, samesite), signing, expiration, session management, etc? Getting and setting the cookie value are the easy part.
For someone entrenched in appsec, most of these are fairly easy. But most developers are not entrenched in appsec. For proof of this, look at the popularity of Auth0.
If this was very simple to solve, securely, those questions, blog posts would not exist.
Something like that.
It reminds me of the fad to get people to use "Javascript CDNs" that are "free" because they track your users with cookies.
However, there are issues with using just a JWT, like inability to revoke them or bottlenecking all user security on one secret key. To solve those and other issues, we use rotating refresh tokens. More about this here: https://supertokens.io/blog/are-you-using-jwts-for-user-sess...
If I understand correctly, you're having me integrate a library on my backend that manages session cookies.
You've implemented refresh tokens and that seems to be one of your major selling points, but I'm confused what benefit that provides?
I thought the use case for refresh tokens in OAuth was that the user can revoke access from the OAuth provider side. But since the user can't go to SuperTokens and revoke their session, isn't the refresh token functionality superfluous?
We don't use normal refresh tokens. We use one time use refresh tokens. This allows to detect token theft in a reliable way for long lived sessions (https://tools.ietf.org/html/draft-ietf-oauth-browser-based-a...).
Also, OAuth is different to session management in that OAuth is for delegation purposes, whilst "a session" can be used to maintain authentication between your own frontend and backend.
In terms of revocation of sessions, our SDK provides functions that can be used to revoke sessions. Soon, we will be making a dashboard that can be used to do the same (and other things)
I'm still a bit confused why you're referencing OAuth here and in the launch announcement while also saying "OAuth is different to session management"
Why have you chosen to use OAuth solutions if you're not solving an OAuth problem? How are you sure it's still the right solution? I see some overlap but it's not obvious to me that OAuth methodologies should be applied here.
In order to detect token theft, we use the general principle of changing tokens on each use. So theoretically, we can use one random string token, that changes on each use and solve the problem in case of sessions.
The problem with that is that it's not scalable since for any request that changes tokens, we need to synchronise calls to that request (https://supertokens.io/blog/the-best-way-to-securely-manage-...).
In order to make things scalable & have this security benefit, we use two tokens. One that doesn't change, and one that is used rarely, but changes... This starts to look like OAuth now.
Pushing it further, we can name those tokens access and refresh tokens. So while OAuth and sessions are different, we can pick specific concepts from OAuth and apply them to sessions.
Soon, we plan on standardising pricing based on our pricing experiments. Thanks for the feedback!
What sort of verification have you done on your solutions? What are the down falls of your solution?
[1] - https://github.com/endiangroup/compandauth
That being said, we have not had any formal verification. We plan on doing an outside code review / audit from a reputable 3rd party in the coming weeks.
Two question for you: - In your solution, I assume there is one JWT per logged in user. If I want to revoke one user's session specifically (without affecting other users who have a similar count), how would I do that? - When would I want to revoke all sessions before some count X?
Apologies if I have misunderstood how your lib works.
Ah I think you've slightly misunderstood, there is a 'counter' per entity, each user has their own separate counter so when you are revoking it is only relevant to sessions related to that users account. This would fall under your database lookup version of JWT management, it's centralised but in the smallest way possible.
That might clear up your second question, you'd want to revoke all sessions like I'd want to 'Log out all other active sessions', logging in to my Spotify on my friends computer last week, and my sisters the week before, I want to log them ALL out.
So when you are verifying an incoming JWT, don't you need to check what the allowed counter is for that session? If yes, then doesn't that require a database / cache lookup for each verification? And if it does, then how are you able to get super fast session verification?
As I understand ST is in effect making the client act as the cache by giving them a refresh token (RT), you delay having to do a central DB lookup until the AT expires and RT is used... You could do the same with CAA, check the DB every X interval (30s) instead of every request, the security implications would be the same (some period of time that no matter who is using the token it will work) as I understand?
From what I've read Theft Protection is a matter of detecting reuse of RT (as I've understood), again with CAA and using the above, you could track each periodic "check" against the master with another counter and embed into the token, if you see a tracking number < or > what you've seen then a Theft has occurred. Would that be the same as ST?
The video about describes 2 edge cases specific to our flow, but I maybe they also apply to your solution?
We can add that to our roadmap. We are also happy to prioritise depending on your use case and commitment! Do reach out to us via email (team@supertokens.io)
You can use it both with REST/GraphQL, and any frontend you may like.
Also supports Oauth like Twitter, FB, Google, Insta, etc...
Has 2FA. MFA on the works...
Anyway if it piqued your interest here are some links: http://accountsjs.com/ Repo in GH: https://github.com/accounts-js/accounts
But you did :) accountjs looks great! Another related hands-off do-it-all solution that I like is https://userbase.com.
This library is written by us to solve for the exact problem you mentioned! It's also being used by Auth0
We're building stuff in a similar space! Would be cool to chat and swap ideas: we're https://www.osohq.com, I'm sam@ the same domain.
We have a self hosted version that uses your own db to store tokens. So you don't need to give us any "user data".
They have a built-in authentication in their distributed database, but not session management. A lot of people is starting to build things with FaunaDB and struggling with auth. In their Slack they even had to open a channel only for authentication doubts.
So if you are looking for a niche, the FaunaDB integration could be a good shot.
We should have something out in a few weeks from now!