Do you use a library like NextAuth? Do you use a provider like Auth0 or Supabase Auth? Do you build your own auth?
I'm building an app using Next.js and Prisma. I'm currently considering Supabase Auth, Auth0, or writing the auth myself. People keep telling me that writing auth myself is a bad idea, and creating truly secure auth is really hard. Although I tried implementing auth with Supabase Auth, and I tried writing my own auth with Google OAuth and Magic Links, and my own auth ended up feeling much nicer and simpler.
I'm looking for some advice from more experienced people. What do you use? What would you recommend? What are the pros and cons of various approaches?
I suspect most people use products like Auth0, not because they are trying to solve those hard problems, but more likely, because it's easy to set up and comforting to hand off that segment to a company that says they are battle-tested and secure, etc.
I personally like writing my own Auth because I can cater to my personal level of paranoia and learn more. Maybe I'm weird in that way, that I like to consider questions like, how short-lived should my token be? Should I issue a new token on every request? Local Storage vs cookie? Should I use a one-time token? Should I store the JWT in memory only on the client? How would I invalidate a user's token at will?
There's lots of interesting questions beyond the basics for sure and I can see how that might be intimidating. Most projects only need the basics though. And if you need more, it might be easier to extend your own implementation rather than some use-case not catered to by a library or service.
At the very least, I think it's wise for dev's to experience writing their own Auth a few times to get a grasp of some the challenges and better understand what those services might be doing for them.
For bigger projects where I need a full-fledged and reliable solution out of the box, I use Ory[1].
Auth is actually a combination of two things: authentication and authorization.
Whatever you do, please do not build either by yourself. It always starts simple and it is guaranteed to get more complex than anyone is willing to maintain (unless you have a dedicated security engineering team)
There are many providers for each. Authentication is about the user's identity and where they belong in the organization (directory), and authorization is about what they are allowed to do based on their identity, role, and attributes.
Cerbos[0] is an open-source authorization solution which integrates with many identity providers to enable your product to implement fine grained permissions. We have integrated with the most popular authentication providers and they can be found on our ecosystem page[1]
Cerbos also has an out-of-the-box integration with Prisma[2] which enables you to fetch only those records that the user has permissions to from your data store - one of the most tricky parts of implementing authorization.
Whatever solution you end up going with, please save yourself some time and do not re-invent the wheel!
[0]: https://cerbos.dev [1]: https://cerbos.dev/ecosystem [2]: https://cerbos.dev/blog/fully-featured-authorization-for-you...
Have a good understanding of cryptographic primitives and what the state of the art is right now for hashing, salting; both at rest and in-transit, etc.
And make sure you follow the principles of least privilege.
Of course this is a fair bit of work and there are specialists in the industry who've made authentication into a service which takes care of following the guidelines and best practices... if you know how to vet them.
They don't always get it right either. Standards and practices evolve. Authentication (and its sibling authorization) require keeping up to date and being vigilant.
[0] https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.S...
I've heard people say that writing your own auth is bad and hard, and the same people fucking it all up with a misconfigured Apache/Nginx server because they don't read/understand the documentation. Mistakes do happen, do your research, discuss it with others and you will learn a lot while creating a secure system that was not that hard to implement in the first place.
We have support for both magic links and google oauth as well as many more options, one of the benefits of going with a provider is that with one integration you'll be able to get more auth products as your auth needs expand and get more complex (ie 2fa with authenticator apps etc). We also handle all of the fun edge cases when it comes to things like email deliverability and ensuring that your magic links end up in your users primary inbox and don't get blocked by spam filters etc.
I'd love to answer any questions you have and help get you up and running with auth so you can get back to focusing on your product!
Here is the documentation for implementing the library with NextJS:
https://supertokens.com/docs/thirdpartyemailpassword/nextjs/...
Btw, the library is backed by Ycombinator.
In my opinion, writing basic auth is simple and safe if you keep OWASP guidelines and other best practices in mind but adding features like SSO and MFA etc is complicated. With that said, almost everything else I tried feels so heavy and slow that I'm sticking with mine for now.
If I've to use prebuilt solutions, I'll pick one that is open source and can be self hosted.
I ended up choosing https://userfront.com/
I think it has the best DX.
1. Easy to implement 2. The burden of security is moved.
I use clerk.dev for almost any project at this point. They take care of auth/ authorization/ database sync.
Sure I could implement these on my own but why not use SSR for next and hook in and have everything setup in minutes so I can focus on the rest of the app that matters more.
We always recommend not building auth by yourself. In the first place it may look simple like its only two input fields and a button (username, password), but to get a really secure solution its a lot more to do. You might need some more authentication methods like passwordless, mfa or identity brokering with google, microsoft, etc.
With ZITADEL we built a solution that combines best of Auth0 (great SaaS solution) and Keycloak (opensource). We believe that a cloud SaaS solution is great to go if its possible to use a cloud solution, but there are always lots of on-prem use cases, thats why we are opensource. https://github.com/zitadel/zitadel
ZITADEL is also focused on B2B usecases, so you can have multi tenancy really easy.
If you have any questions just let me know.
I spent something like 3 weeks this year on refactoring related to auth systems -- it's endlessly frustrating to me and I blame the fact that there's no web standard for login
I avoid 3rd party providers like auth0 -- I believe that they're better at security than me, but 1) they're a large target, 2) they're solving a harder problem and 3) giving the keys to every user acct to auth0 et al feels like too large of a compromise to make on behalf of my users. (that said, if I'm breached, I've given data to a worse third party).
also not wild about oauth, esp from a consumer perspective -- too easy to expand scope later and demand privacy leaks in exchange for logging into your acct
If your application fits into Sandstorm's model of grains[3]_, then the security benefits of Sandstorm are many.
.. [1] https://sandstorm.io/ .. [2] https://pypi.org/project/djangolovessandstorm/ .. [3] https://docs.sandstorm.io/en/latest/using/security-practices...
Reading the docs from top to bottom, and diving into the source code makes me believe that "you should never roll your own auth" should be an addendum to "you should never roll your own crypto". The number of edge cases and gotchas is simply mind-boggling. It's not about being a good enough programmer to cover yourself, but about years of collective experience dealing with all sorts of exploits and browser shenanigans.
[1] https://docs.spring.io/spring-security/reference/servlet/aut...
- NextAuth is bare basic but gets you going real fast. The most examples - both simple and complex - and works with so many DB adapters.
- Clerk was probably the nicest developer experience: fast, works with many frameworks, and great community. But there’s not a lot of support outside of basic examples.
- Supabase Auth is a little more mature than Clerk and ultimately what I ended up choosing. But it doesn’t have the out of box features: orgs, different environments, MFA.
As I said, landed on Supabase for the application database. It makes a lot of sense and works great.
I tend to use one API endpoint for pass phrase authentication, which returns a token (any sufficiently complex unique string, such as base64 (or hex) of a >128 bit unique key . Many auths use a hash, to which I say don’t get carried away)
The token is a temporary throw away credential that should:
* expire (say 8 hours)
* times out after inactivity (say 2 hours)
* unique to session (allows distinction among concurrent sessions). I hash the token to create a unique session ID for logging
I only store these in cache, not the db so they expire and cannot be recovered (hashed again to create a trackable unique value.)
Personally, I am torn.
As a developer, magic links are awesome. You put a new project online, and everyone on planet earth already is a user. Well everyone who has an email.
But from a user perspective, it is more cumbersome. For one because the switch between email and website. And because the typical magic link implementation invalidates the link after one use. So if I don't keep the cookie, I have to do the "enter email, receive email, click link" dance again. Entering my email and a password is faster.
I only wanted read-only social network login.
There was an official library in the language of my choice.
It was free (at my level of use).
The only thing I need to keep secure is the API tokens for Facebook / Twitter / GitHub etc. I don't even bother storing anything other than the user's ID, current name, and service.
If someone hacks my service, they won't be able to do anything nefarious with the user's data.
Building your own is a nightmare. If a login provider changes their API flow, Auth0 are incentivised to fix it - rather than passing the buck to me.
That said, I have a related question I'm hoping the security nerds here can help with: I know it's bad practice to reveal the existence of an account during registration, because it gives an attacker a way to know if a user has an account. So on registration, if the email already exists on another account, you shouldn't say "that account already exists" or do anything that would reveal the account already exists. To me, that means you should always send the user to a "registration successful, check your email" page and then if they already exist, send an email saying it exists with links to password reset & login. That means that the app must be unusable until the user validates their email. But that seems annoying and is not what many sites do. For example, I just tried on shopify, and if the account already exists, they send you to the login page. If not, they log you in automatically. So, for shopify I could in theory scrape using a email list and find who has accounts. To see why this is bad, think of shadier sites (my saas is not). So, my main question: am I making too big a deal about this security requirement or the usability problem it presents? Am I missing some alternative?
Related, I'm thinking about letting users send an email to bot@mysaas.com or text 5558675309, which would respond with a "finish registration" or "login" page and auth token accordingly. This would let them skip the verify email step. Is this a bad approach?
I'm the founder of Hellō[0], and if you are targeting consumers or individual professionals and want to give them choice, check it out.
As some background, I cofounded the OpenID Foundation, drove creation of OAuth 2.0 and what became JWT, and gave a popular Identity 2.0[1] talk years ago.
[0] https://hello.coop & https://hello.dev [1] https://www.youtube.com/watch?v=RrpajcAgR1E
Yes the problem these days is a lot of commercial providers want this to become "common knowledge" and for it to be "best practice" to use their systems. But what happens if Okta has a data breach and you don't even know if your users were affected? (This happened)
I strongly believe in rolling your own auth:
1. It keeps it simple
2. You control the data that's a critical part of your system
3. Okta and Auth0 are giant targets because they have so many peoples' creds - you aren't
4. Even if you do use something like Auth0, you still need to implement authorization somehow. Of course, there are people who want to sell you solutions for that too...
Use libraries for the underlying primitives like bcrypt and JWT's. Do the rest yourself. Keep it simple.
Oh, and keep it simple.
The one good reason I've seen recently to use third party auth services is because they often support MFA. But how many companies actually need that? I've worked for a bunch of companies over my career and the amount of times I've had to implement/add MFA is 0.
In addition, they have easy means of customizing the User object, querying external data sources, etc. Highly recommend.
Hashing the password with Bcrypt and auth with session-cookie for login. It's not easy but once you start implementing those on your own, you will learn and understand more.
https://github.com/irrelevelephant/nextjs-hello
Its interface is essentially just a login button component, and functions to retrieve the user session state on both the client/server.
If you're not using Next.js, you may want to use Hellō directly - it's a simple OIDC provider with some convenient benefits.
In my current project I do away with accounts completely and just email a link that sets a cookie for 30 or 90 days [1]. I think the Auth you choose highly depends on the money/privacy/sensitivity/fraud potential of your project.
Truth be told, I usually hate having to do it. That said I’ve never found a reasonable alternative.
There are usually differences in each set up that require customisation (for example magic links like you mentioned) and trying to integrate a platform like auth0 feels like it would be as much work.
I also don’t like the idea of the inevitable migration when I need something else it doesn’t offer, it goes out of business or gets acquired.
At a high level:
1. Claim and prove ownership of a public key 2. Sign a session claim that links the handle with the public key 3. Service verifies the claim's signature was signed by the corresponding private key
It’s not a rocket science unless you’re big enough to bother about tricky use cases and unique security requirements.
Despite what Auth providers are trying to promote.
PS: I mean authentication only. Authorization seems like a different beast with different challenges, sometimes tightly coupled with your business logic.
That way, you have as much control over it as if you built it yourself but it comes ready made and off the shelf.
The open source options are: Keycloak, SuperTokens, Ory and many more
(Im the cofounder of SuperTokens)
Django-auth-ldap with python-ldap when I need to use ldap.
Django-allauth when I need oauth providers (google github etc)
Requests-oauthlib integrated with django auth when I need a more customized solution.
I've never understood the reason to use anything else ...
I'd be interested to know points to migrate away from firebase/google dependencies. I struggle to use anything else as it's so easy to get all the social logins set up...
But you? It depends on what your goals are :P
Crypto is the thing I won't touch with a ten foot pole.