9 ms·
OAuth from First Principles
- candiddevmike 2y agoNo mention of JARM unfortunately.
- apitman 2y agoDPoP would top my list, but honestly I'm glad they stuck to the core stuff.
- shreddit 2y agoQuite funny they ask “why would you want to reinvent the wheel” when they just did that… And why do most of these “Auth0” replacements only implement nextjs?
- deleted 2y ago[deleted]
- n2d4 2y agoWe gotta start somewhere, and Next.js is popular right now — we're working on some cool non-Next stuff though (eg. auth proxies that can provide user info to any server, which we can hopefully launch within the next weeks). Regardless, the focus of this blog post is on OAuth, not Stack Auth =) I appreciate the feedback though.
- shreddit 2y agoYes, the blog post is very informative (although the images do not scale well on mobile). My previous post was based on the phrase “open-source Auth0” (in your blog post) and we use Auth0 (and don’t like it). But all of out apps are react, not nextjs
- 3dbrows 2y agoI’m currently evaluating Auth0 and other similar services with a view to migrating from Cognito. May I ask what you don’t like about it?
- grinich 2y ago(plugging my startup- hope that’s ok!) we’ve had lots of folks migrate from Cognito to WorkOS. Lots of more features, modern API, and better extensibility. More here: https://workos.com/docs/migrate/aws-cognito https://workos.com/docs/migrate/aws-cognito
- chairmansteve 2y agoThanks for this, I will work through it. If you happen to be looking for future blog posts: One thing that would help me and probaby a lot of other people is to show the flow using API calls in Postman. Currently I am planning to reverse engineer example code in an unfamiliar framework...
- apitman 2y agoWheels should be reinvented once in a while, just to make sure there's not a better way to do it. They just shouldn't be reinvented by everyone all the time when there are perfectly good solutions available.
- mooreds 2y ago> And why do most of these “Auth0” replacements only implement nextjs? Probably because it's hard to support different languages. Even if all the replacements support OIDC (not a given) there are still subtle differences in implementation and integration. That said, check out FusionAuth! We have over 25 quickstarts covering a variety of languages and scenarios. (I'm employed by them.) https://fusionauth.io/docs/quickstarts/ https://fusionauth.io/docs/quickstarts/ We're free if you don't need advanced features and run it yourself, as documented here: https://fusionauth.io/blog/fusionauth-on-fly-io https://fusionauth.io/blog/fusionauth-on-fly-io
- mattgreenrocks 2y agoThank you for writing this up. Helps me understand all the steps and why they exist.
- mannyv 2y agoThe 'why' is what makes this post good. Lots of posts just saw 'do this.' But to learn you should really know the 'why.'
- 0cf8612b2e1e 2y agoThis is rendering poorly on my phone. Had to enable desktop mode to see the diagrams which are unwise cut off.
- codetrotter 2y agoSome of the pictures stick out beyond the right side of the screen, and scrolling felt slightly sluggish(?), but aside from that I found the page to look pretty ok in Safari on iPhone.
- n2d4 2y agoThanks for the catch, fixed it now!
- Sn4ppl 2y agoNow it looks great
- bgschiller 2y agoNice writeup, this is also how I think about OAuth. I gave a very similar talk at Develop Denver back in 2018: https://www.youtube.com/watch?v=7rGkz9Ib4fQ https://www.youtube.com/watch?v=7rGkz9Ib4fQ My slides even look similar to your diagrams: https://brianschiller.com/lets-build-oauth/#/31/10 https://brianschiller.com/lets-build-oauth/#/31/10
- taeric 2y agoI'm still not entirely clear on if I should abandon implicit flow for a static site to get credentials. Easy enough to switch it to the CODE flow, but that gets you a refresh token with AWS and that feels a bit more risky to have on the client side.
- candiddevmike 2y agoYou (typically) only get a refresh token if you ask for offline access in your request scope AFAIK. It's not the default (online is).
- taeric 2y agoFor AWS Cognito's Token endpoint? Where is that documented? I'm also not seeing that behavior, as I don't have that in my scope and I do get a refresh token if I do the CODE flow.
- candiddevmike 2y agoI'm referring to the openid standard I guess[1], it looks like AWS Cognito does something different (they don't support offline_access, but they always issue a refresh_token from what I'm reading). 1 - https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess https://openid.net/specs/openid-connect-core-1_0.html#Offlin...
- taeric 2y agoYeah, if you do a CODE flow, you get three tokens. Implicit is only access. They at least have decent support to guard api access using these.
- CuriouslyC 2y agoYou can do stuff to keep the lifetime down on the refresh token.
- 2y ago
- lxe 2y agoI haven't really dove deep into oauth flow since 2015 or so until I started working on a little side project choosing to go with AWS Cognito, and the whole PKCE part of the flow was new to me. This explains them well.
- mooreds 2y agoAlso recommend reading the OAuth Security BCP[0]. Kinda dense and there's bit of jargon, but consolidates person-decades of wisdom around this topic. 0: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics https://datatracker.ietf.org/doc/html/draft-ietf-oauth-secur...
- deleted 2y ago[deleted]
- mooreds 2y agoTo be fair, they recommend reading this doc at the end of their article.
- hn_throwaway_99 2y agoI thought it was somewhat funny that all of the points highlighted in the "Attack #1: Big Head's credentials are exposed" section are exactly how Plaid works.
- Spivak 2y agoYep, Plaid is put in a rough position of having to make something work across a bunch of financial institutions that can't or won't enable applications to have secure access. Plaid's existence and popularity is the canary that banks are way behind on features that users want.
- mooreds 2y agoThis is why I avoid plaid at all costs. Hopefully FAPI and some of the banking open standards will (eventually) help with this.
- tomjakubowski 2y agoNot true anymore, at least for some banks. On connecting to Plaid, Chase provides an oauth flow, and Plaid never sees your credentials. Plaid announced this level of integration with Chase in 2018. Unsure when it was implemented. https://plaid.com/blog/chase/ https://plaid.com/blog/chase/
- apitman 2y agoMint was the same way back in the day. I think Chase still doesn't support hardware tokens or authenticator apps. It's insane that banks are somehow the furthest behind in many security best practices.
- racl101 2y agoI would love to learn all architecture lessons in the context of Silicon Valley.
- tonymet 2y agowith Bighead, and possibly Jinjiang , exclusively
- rguldener 2y agoVery cool! I love how you build on the need for each step one by one. We implemented (O)Auth for 250+ APIs with Nango and wrote about our experience here: https://www.nango.dev/blog/why-is-oauth-still-hard https://www.nango.dev/blog/why-is-oauth-still-hard
- focusedone 2y agoThis is great!
- michalmiko 2y ago[flagged]
- bcherny 2y agoThe site seems to have been hugged to death. Does anyone have a mirror link?
- bcherny 2y agoIn case anyone else needs it: http://archive.today/BxSoe http://archive.today/BxSoe
- ultimoo 2y agoIf you’re building a new SaaS today would you simply implement this natively in your stack or go with a vendor like auth0?
- lknuth 2y agoI hve just implemented this after we moved away from SuperTokens. My takeaway is that its easier than you'd think (there are libraries that do interaction with the SSO provider for you) and you can fine tune it to your liking (for example, more involved account linking). If you're starting out though, probably go for a SaaS in the beginning. But be sure to have monitoring for pricing and an option to close account creation, these things can become expensive fast.
- tgma 2y agoI am curious what your issue with Supertokens was?
- lknuth 2y agoMany. We used the NodeJS Version of it, which has pretty poor error handling. When it breaks, it breaks hard (runtime errors with no message or stack trace) Security. You can not deactivate certain unsave mechanisms. For example, if you send it an ID token, it will not verify the aid claim, allowing Anny valid token from the same SSO provider. API stability. We're consuming their API from a mobile app. But every major version (about five a year) changed the REST API without backward compatibility or versioning. Its fine if you use their lib and keep parity, but that's really only possible on the web. All of this was with their self hosted offering, I haven't tried their hosted one.
- kirubakaran 2y agoYou could use something like https://docs.allauth.org/en/latest/ https://docs.allauth.org/en/latest/ auth0 is too expensive for new SaaS imho
- pphysch 2y agoIf you aren't in a rush, it's worth learning and the implementation won't be too big.
- stronglikedan 2y agoMan I wish I would have run across this when you first posted the blog. I just spent the last week learning all of this in pieces and by trial and error! Great writeup!
- animal_spirits 2y agoI just watched this lecture on Oauth2 and OpenID, good if you prefer video formats https://www.youtube.com/watch?v=996OiexHze0 https://www.youtube.com/watch?v=996OiexHze0
- bityard 2y agoI love the Silicon Valley references. One of the funniest shows ever made. I don't see it talked about much on HN, maybe it tends to hit a little too close to home?
- TacticalCoder 2y agoBoth Silicon Valley and The IT Crowd (the british version) are amazing. Although not comedy I also strongly recommend Halt and Catch Fire.
- mooreds 2y agoWe've used both in our doc. It's a great way to be playful and nod to geek culture. Still waiting for the cease and desist :)
- jiggawatts 2y agoAnd this is why it takes me a solid minute to log in to my CRM web app to submit my timesheets for the day, a task that takes only 5 seconds.
- apitman 2y agoSounds like a bad implementation. There's nothing inherent to OAuth2 that makes it slow (thought the redirects to create a latency floor). If you want a good experience try logging in to my website https://takingnames.io/ https://takingnames.io/. Once you have an identity on LastLogin it's lightning fast.
- jiggawatts 2y ago"Nothing inherently bad" other than: 1. Tens of kilobytes of JS that is executed exactly once, so is not amenable to JIT optimisation. 2. A strictly sequential series of operations with zero parallelism. 3. Separate flows for each access token, so apps with multiple APIs will have multiple such sequential flows. Thanks to JS being single-threaded, these will almost certainly run in sequence instead of in parallel. 4. Lazy IdPs that have their core infrastructure in only the US region, so international users eat 300ms per round trip. 5. More round-trips than necessary. Microsoft Entra especially uses both HTTP 1.1 and HTTP/2 instead of HTTP/3, TLS 1.2 at best, and uses about half a dozen distinct DNS domains for one login flow. E.g.: "aadcdn.msftauth.net", "login.live.com", "aadcdn.msftauthimages.net", "login.microsoftonline.com", and the web app URLs you're actually trying to access and then the separate API URLs because only SPA apps exist these days. 6. Heaven help you if you have some sort of enterprise system that the IdP needs to delegate to, such as your own internal MFA system, some Oracle Identity product, or whatever. I've seen multi-minute login flows that literally cannot run faster than that, no matter what. This is industry-wide. I stopped using chatgpt.com because it makes me re-authenticate daily (why!?) and it's soooooooo slow. AWS notoriously has its authentication infrastructure only in the US. Microsoft supports regional-local auth servers, but only one region, and the default used to be the US and can't be changed once set. Etc, etc...
- apitman 2y ago
- apitman 2y agoThis is fantastic. I've implemented OAuth2 4-5 times over the past few years. It seams overly complicated at first, but over time I've come to understand more of the vulnerabilities each piece of complexity exists to mitigate. Every time I've thought I could do it simpler, I eventually discovered a vulnerability in my approach. You get basically all that knowledge here in a concise blog post. This is going to be the first thing I link anyone to if they're interested in learning OAuth. One gripe from Attack #3[0]: > The solution is to require Pied Piper to register all possible redirect URIs first. Then, Hooli should refuse to redirect to any other domain. There's actually a another (better IMO) solution to this problem, though to date it's rarely used. Instead of requiring client registration, you can simply let clients provide their own client_id, with the caveat that it has to be a URI, and a strict prefix of the redirect_uri. Then you can show it to the user so they know exactly where the token is being sent, but you also cut out a huge chunk of complexity from your system. I learned about it here[1]. [0]: https://stack-auth.com/blog/oauth-from-first-principles#attack-3 https://stack-auth.com/blog/oauth-from-first-principles#atta... [1]: https://aaronparecki.com/2018/07/07/7/oauth-for-the-open-web https://aaronparecki.com/2018/07/07/7/oauth-for-the-open-web
- awans 2y ago> Then you can show it to the user so they know exactly where the token is being sent Unfortunately, most major websites end up hosting an endpoint that will redirect users to a separate URL provided as a query parameter. This means that users may easily be misled about where the token is, in fact, being sent. [0] - https://sec.okta.com/articles/2021/02/stealing-oauth-tokens-open-redirects https://sec.okta.com/articles/2021/02/stealing-oauth-tokens-... [1] - https://datatracker.ietf.org/doc/html/rfc6819#section-4.2.4 https://datatracker.ietf.org/doc/html/rfc6819#section-4.2.4
- apitman 2y ago> most major websites Is this true? Do you know of any major ones offhand? That would be surprising to me. Thanks for sharing [0]. I found its discussion of shared subdomain cookies useful. However, I believe all the vulnerabilities in the OAuth section would be mitigated by using PKCE and not using the implicit flow, even if you leave the open redirect. Am I missing anything there? As for open redirects in general, it is an important problem. As an authorization server, if you want to protect against clients that might have an open redirect (and as you indicate eventually one will), while still using the simple scheme I mentioned above, I can think of a few options: 1. Require the client_id to exactly match the redirect_uri instead of just a prefix. This is probably the most secure, but can result in ugly client IDs shown to the user, like "example.com/oauth2/callback". Of course clients can control that and make it something prettier if they want. 2. Strip any query params from the redirect_uri, and document this behavior. That should handle most cases, but it's always possible clients implement an open redirect in the path itself somehow. You could also check for strings like "http", but at some point there's only so much you can do. 3. Require clients to implement client metadata[1], so you can get back to exact string matches for redirect_uri. This is a very new standard, and also doesn't work for localhost clients. [0]: https://sec.okta.com/articles/2021/02/stealing-oauth-tokens-open-redirects https://sec.okta.com/articles/2021/02/stealing-oauth-tokens-... [1]: https://datatracker.ietf.org/doc/html/draft-parecki-oauth-client-id-metadata-document https://datatracker.ietf.org/doc/html/draft-parecki-oauth-cl...
- palk 2y agoProbably the best OAuth tutorial on the internet. Also it's amazing marketing, it just gets scarier every paragraph. By the end you're 100% put off implementing OAuth yourself haha
- klabb3 2y agoDo regular people verify domains? It feels like the entire domain based trust model has been eroded by in-app browsers eliding the chrome for “simplicity” and even bank/visa official payment gateways that are redirecting you all over weird partner domains and microservice endpoints. Plus of course lack of education and mantras that mortals can follow at all times. If users don’t verify domains, isn’t good old phishing more effective, like the $5 hammer in that xkcd?
- n2d4 2y agoRegular people may not but password managers do. Maybe not everyone, but at least security-conscious people would grow suspicious when their password manager doesn't autofill credentials on a page, and wouldn't immediately jump to manually entering it. (SSO also reduces the attack surface of phishing, though of course then the attacker just has to phish the identity provider's credentials instead.)
- ilrwbwrkhv 2y agoNice article but once again, using "open source" as a marketing gimmick is just a bad practice. If you really want to do that, have self hosting, contribution and other things front and center and don't take VC funding.
- n2d4 2y agoIt's really not just a marketing gimmick — it's the sole reason why we are building Stack Auth, instead of going for one of the existing proprietary managed auth solutions. Trust me, we wouldn't spend time building this if we didn't believe in the one thing that makes us different. I'll quote myself from elsewhere: > Both Zai and I care a lot about FOSS — we also believe that open-source business models work, and that most proprietary devtools will slowly but surely be replaced by open-source alternatives. Our monetization strategy is very similar to Supabase — build in the open, and then charge for hosting and support. Also, we reject any investors that don't commit to the same beliefs. Fortunately, nowadays a lot of VCs understand this (including YC, who has a 10+ year history of investing in FOSS companies); we make sure that the others stay far away from our cap table.
- ilrwbwrkhv 2y agoThey will eventually want you to have an exit. And there lies the problem. You should have gone for something like futo if you wanted the money. Right now there is an ideological dissonance in what you're doing. Same with supabase et al. The only reason the real open source is what the world is built on, is because there is a guarantee that they will never need an exit and the community will always exist.
- myrealusername 2y agoNice introduction. One thing I missed though, is the introduction of the client secret in attack #6, which actually solves the problem if Piped Piper is exchanging the code for a token from its own server. PKCE is only strictly necessary if you cannot ensure that the client secret is not extracted, which could be the case if it's stored in a native app on for instance a smartphone.