HACKER Q&A
📣 lumenwrites

What do you use to build auth?


How do you build auth for your SaaS apps?

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?


  👤 jaeming Accepted Answer ✓
I too have seen the articles proclaiming that devs should stop implementing auth themselves and instead use some Auth as a service product. After all Authentication is hard to get right, right? Actually the basics are really easy. Using a short-term JWT and bcrypt to salt passwords is like maybe 10 lines of code. The thing is, most of the truly hard Auth problems I've had to solve in my career took a highly custom approach anyway.

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.


👤 keraf
For small JS projects, I use Passport[0] as it is quite simple to implement and has ton of examples (including how to use it with Next).

For bigger projects where I need a full-fledged and reliable solution out of the box, I use Ory[1].

[0] http://www.passportjs.org/ [1] https://www.ory.sh/


👤 emreb
Disclaimer: I am the co-founder of Cerbos[0]

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...


👤 agentultra
If you are going to implement yourself I would recommend familiarizing yourself with the NIST SP 800-63b [0] guidelines.

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...


👤 olavgg
I write my own, and I mostly use session cookies. I do support login from other OpenID connect providers like Azure Active Directory(AAD) in addition to old email/username/password + 2fa with otp. Basically when they have successfully authed I create a new session cookie for them. The disadvantage is that when the user logout AAD, they still have a session in my application. Though I can always force logout by having a background job that validates that the user is still logged into AAD.

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.


👤 jelambs
Hi! Disclaimer, I'm the co-founder/cto at Stytch[0]. We built Stytch because we went through the pain of building auth both in house and with incumbent players and wanted a better tool for developers building authentication. Stytch is flexible to enable you to build the experience that you want for your users but we do all the heavy lifting when it comes to both authentication and authorization.

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!

[0] https://stytch.com/


👤 ciprix
I'm currently working on a project with the same stack: NextJS + Prisma + Postgresql and I started to implement this open source auth library:

https://supertokens.com/

Here is the documentation for implementing the library with NextJS:

https://supertokens.com/docs/thirdpartyemailpassword/nextjs/...

Btw, the library is backed by Ycombinator.


👤 mohitsingh
Well, I wrote one with rust and actix-web for exact same purpose.

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.


👤 Leftium
I researched and tried several hosted auth solutions.

I ended up choosing https://userfront.com/

I think it has the best DX.


👤 jamesperkins
For most projects these days I will use a provider for two reasons:

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.


👤 fabig
Disclaimer I work at ZITADEL and am one of the co-founders.

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.


👤 awinter-py
I try wherever possible to use tools but it's tough -- I have some signup features that need to integrate tightly with login flows, and stock framework auth is often not flexible enough

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


👤 troyjfarrell
I build my apps on Sandstorm[1]_. Sandstorm provides authentication as a part of the platform. For Django applications, I wrote Django Loves Sandstorm[2]_.

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...


👤 zkirill
I sleep better at night thanks to Spring Security and KISS. [1]

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...


👤 johnbellone
I’ve been tinkering in this space for about a year now. They all have their own problems.

- 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.


👤 inphovore
I write my own. Though my platforms do not socially integrate.

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.)


👤 mg
From a user perspective, how does everyone here feel about magic links vs email and password?

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.


👤 edent
For me, Auth0 was the quickest and easiest.

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.


👤 shireboy
Wrestling with this now for a side project. I've landed on .NETCore+ASP.NET Identity after getting frustrated with NuxtJS+fastify-auth, but that's really because I'm more familiar from my day job and didn't like the SPA road Nuxt was forcing me down.

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?


👤 dickhardt
Your question is missing a couple key inputs. Q: Is your SaaS app targeting enterprise use cases, where the customer will want to enable SSO and centralized provisioning? Keybase is a reasonable choice in this case because of the SAML and SCIM support. Q: What is your expected revenue per user? Auth0 solves many problems out of the box, but is priced on MAU which can be prohibitive if your revenue per user is low, but deals with lots of complicated issues if not and lets you focus on building your app.

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


👤 davedx
> People keep telling me that writing auth myself is a bad idea, and creating truly secure auth is really hard.

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.


👤 recroad
Auth0. I've tried a bunch of third parties and I found Auth0 to have good documentation, a great free plan, good support, and a user experience that is quite good. Some of the Rules/Actions terminology is a bit confusing, but overall the management UI and APIs are quite good.

In addition, they have easy means of customizing the User object, querying external data sources, etc. Highly recommend.


👤 kinqsley
In the past few years, from zero knowledge to implemented the same auth features including login, registration and reset password etc in past company projects.

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.


👤 jtwebman
Simple hashed passwords and a few emails are not hard to make myself so I do that. Also makes it much easier to tie in roles which are much different for each project. It really isn't that hard to build a simple one yourself and gives you much more control and one less dependency on an outside service.

👤 1337shadow
Whatever the server side framework offers natively, plus framework specific plugins such as for OTP login or whatnot, depending on the project. If your framework doesn't take care of authentication for you, it's probably not production ready.

👤 irrelevelephant
I built a Next.js library for this purpose using Hellō and iron-session. This lets me roll a new application with social login without needing to register with Google/Apple/other providers.

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.

https://www.hello.dev/


👤 janesconference
Implementing simple auth is not that hard, with JWTs. But you need to use a service anyway for mail (confirm password, reset password etc.), so in the end it's not worth. These days I use Supabase auth and it works.

👤 tppiotrowski
If I want to put something together fast I use the default AWS Cognito and Firebase Auth widgets. I think Firebase Auth has more third party sign in options.

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.

[1] https://tedpiotrowski.svbtle.com/shade-map-pro


👤 aosaigh
I usually write it myself with Django, Django REST Framework and JWTs alongside either Vue.js or Ember (and their with libraries).

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.


👤 ydnaclementine
Always go back to devise in rails land. It isn't worth the effort to integrate with an external service for the side projects I work on, but maybe I should try it just once

👤 jshawl
I'm exploring a signature-based authentication scheme here: https://github.com/jshawl/proof.im

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


👤 aristofun
I bet just passport js with its many strategies is a good enough option for 98% of SaaS startups out there.

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.


👤 gedy
Not exactly your question, but since you are using NextJS I highly recommend you use its API route[0] support to proxy your backend API calls, which allows you to avoid exposing auth tokens, etc to client web front end

[0] https://nextjs.org/docs/api-routes/introduction


👤 moomoo11
I use firebase auth because it’s free at any scale and it takes minutes to set up. It’s backed by google so I’m not kept up at night.

👤 paulgb
We've rolled our own (zero frills) so far, but are looking at PropelAuth (https://www.propelauth.com/) to add MFA and other bells and whistles and we like what we see. (Full disclosure, they've become friends of ours through YC)

👤 mind-blight
I just started using FusionAuth and am a fan. It's like a cheaper, better documented Auth0 that you can self-host.

👤 advaitruia
To get the best of both "build" and "buy", I recommend using one of the open source alternatives.

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)


👤 spapas82
Django auth only for projects that have their users in the database.

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 ...


👤 whiskey14
I've tended just to go with the quickest and easiest thing for me, which is firebase + jwts.

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...


👤 spacemanmatt
I got used to Keycloak and now I like to use it for pretty much everything

👤 dustymcp
We use identity server from M$ its fairly good and works for our purposes, its easy to bind clients etc. we can always expand it if we want it to do more.

👤 withinboredom
I just spent the last week building one using webauthn. It’s actually pretty awesome and I’ll probably open source it in the next few days.

👤 rusticpenn
I am surprised that I did not find keycloak here…

👤 kache_
As an IAM engineer who's been doing this shit for way too long, I'd write my own auth.

But you? It depends on what your goals are :P


👤 welder
I use a library called Flask-Login that provides the framework for good session cookie website auth.

👤 davzie
Out of the box with Laravel and sometimes Socialite if I need to integrate other social logins.

👤 bennyp101
Currently a lot of stuff is organically grown, but moving to keycloak for a lot of things.

👤 midasuni
OIDC or x509 on the proxy and it passes the username through

👤 Trufa
next-auth has been the best I've ever used.

👤 lovetocode
I have used AWS Cognito and Azure AD B2C

👤 asdev
Firebase auth is really easy to use

👤 wdb
There is oidc-provider for Node

👤 moltar
Cognito

👤 dhzhzjsbevs
Auth isnt hard, built lots of auth systems.

Crypto is the thing I won't touch with a ten foot pole.