Engineering decisions

Auth: build, buy, or self-host

EdgeBrain Studios12 min read

Buy it.Unless enterprise SSO pricing has become your largest infrastructure line item, or a regulator forbids a third party holding identity data, in which case self-host Keycloak or Ory. Build your own essentially never. And note that this is a three-way decision rather than the two-way one the phrase “build vs buy authentication” implies.

The number that decides it is not your monthly active user count. It is how many enterprise SSO connections you sell, because every managed vendor prices those per connection, and that line grows with your best customers rather than with your traffic.

Something to know about the rest of the internet here: search this question and every result on page one is an auth vendor. The widely repeated claims, that under five percent of teams should build and that do-it-yourself compliance runs $50,000 to $200,000 a year, come from companies whose revenue depends on that conclusion. Not necessarily wrong. Just not evidence. We have no auth product, so nothing here rides on the answer.

The three options, and what each one actually means

Buy. A hosted provider holds your users and issues your tokens: Clerk, Auth0 (now Okta Customer Identity Cloud), WorkOS, Stytch, Supabase Auth. You integrate an SDK and someone else is on call when login misbehaves at 3am.

Self-host.You run a maintained identity server on your own infrastructure: Keycloak, an Apache-2.0 project now incubating at the CNCF and distributed on Quarkus since version 17, or the Ory stack, which is Kratos for identities, Hydra for OAuth2 and OIDC, and Keto for permissions. You’re not writing a password hasher. You’re running software that already implements OIDC and SAML 2.0, and you own its uptime, upgrades and database.

Build.You write the identity system: hashing, session issuance and revocation, email verification, password reset, TOTP, WebAuthn, account linking, rate limiting, audit logs. The vendor posts argue hard against this and they’re right for the wrong reason. Building loses because self-hosting exists and is far cheaper, not because buying is the only alternative.

Auth provider pricing at 1k, 10k and 100k MAU

Every figure below is the vendor’s published list price, read in August 2026, for consumer-shaped authentication: email and password, social login, MFA, no enterprise SSO. Re-check them before you budget. Auth pricing pages change more often than auth products do.

Provider1,000 MAU10,000 MAU100,000 MAUWhere the list price stops
ClerkFreeFree$1,025/mo50,000 free, then $0.02 per retained user to 100,000
Supabase AuthFreeFree$25/moPro includes 100,000 MAU, then $0.00325 each
WorkOS AuthKitFreeFreeFreeFirst 1M MAU free, then $2,500/mo per extra 1M
Auth0 B2CFreeFreeSales quotePublished tiers end at 50,000 MAU
Keycloak or Ory, self-hostedInfrastructure only, flat in MAUYour Postgres bill and your on-call rota

Read the 100,000-MAU column twice. Clerk and Supabase differ by roughly forty times for the same user count, and neither is being dishonest. Clerk prices a complete identity product with prebuilt components, Supabase prices auth as a bundled feature of a Postgres platform you pay for anyway. That $25 is a base fee on a small compute instance, and a real 100,000-MAU workload spends more than that on compute however it authenticates.

Then notice that four of the five rows are free at 10,000 MAU. Consumer authentication is not where the money is any more, which is the entire reason the next section exists.

The enterprise SSO surcharge is the real pricing cliff

Every result that tells you to buy auth quotes the MAU price. Almost none of them lead with the per-connection price, and the per-connection price is what actually lands on your invoice once you start selling to companies that have an IT department.

Per connection versus per MAU

WorkOS publishes SSO at $125 per connection per month for the first fifteen, sliding to $100 for sixteen to thirty and $80 up to fifty. Directory Sync is priced the same way, separately. Clerk includes one enterprise connection and charges $75 a month each for the second through the fifteenth, on top of a $25 Pro base and a $100 B2B add-on. Auth0 gates enterprise connections behind higher tiers, and its B2B Professional plan starts at $800 a month for 500 MAU against $240 for the B2C equivalent: the same product, priced by who is buying.

Supabase prices the same capability along a different axis: fifty SSO users included, then $0.015 per SSO MAU. Not per connection.

That difference decides your bill. Fifteen enterprise customers on WorkOS is $1,875 a month, $22,500 a year, before one of their employees logs in. The same fifteen on Clerk is roughly $1,175 a month at list. On Supabase, assuming 3,000 SSO users across all of them, about $45. Per-connection pricing punishes you for having many small enterprise customers; per-MAU pricing punishes you for having few large ones. Nobody tells you which shape you are before you sign.

Note also that Clerk publishes connection pricing to fifteen and WorkOS to one hundred, then both say “contact us.” A price that stops being published is about to be negotiated, and your position in that negotiation is a codebase with the vendor’s SDK in it.

Where self-hosting overtakes buying

On Keycloak, a SAML connection is a configuration entry. The marginal cost of the twentieth one is zero. So there’s a crossover, and it’s lower than the market wants you to believe.

Our own estimate, inputs exposed so you can substitute yours. Two redundant instances plus managed Postgres with backups: $120 to $300 a month. Steady-state maintenance once running: three to six engineer-hours a month. A one-off production build of three to six weeks, covering deployment, your own login screens, MFA, account recovery, monitoring and a runbook.

At a loaded rate of $80 an hour, four hours a month is $320, and a four-week build amortised over three years adds $356. Call it $880 a month all in. Against WorkOS at $125 a connection that crosses at about seven connections; against Clerk’s $75, about twelve.

Seven to twelve is not a law. It moves with your loaded engineering rate, which you know and we don’t, and it assumes you already run Postgres, already deploy containers and already have someone who gets paged. If any of those is false, buying wins for longer. Working a number forward from its inputs instead of quoting a headline is the same discipline as forecasting what an AI feature costs to run per user.

What self-hosted auth with Keycloak or Ory really involves

Three things people underestimate, in the order they bite.

You still build the parts your users see

Keycloak ships login pages. They look like Keycloak login pages. Theming them is real front-end work, and every custom theme is a hostage to the next major version. Ory takes the opposite position and expects you to build the UI, which is honest without being free. Budget interface work either way. This is product surface rather than infrastructure, and it belongs with the rest of your application front-end engineering.

The upgrade tax is real and it is quarterly

Keycloak releases several times a year and its history includes genuine breaking changes. Version 17 moved off WildFly to the Quarkus distribution, the admin console has been rewritten, and adapter libraries have been deprecated. You don’t get to skip upgrades here, because this is the one component where a known CVE is a company-ending event. Somebody owns it by name.

Availability becomes your problem, including the failure mode

When the identity server is down, your product, your admin panel and your internal tools are all down. Run it on infrastructure that fails independently of the application it protects, and decide in advance whether an outage lets existing sessions continue or ejects everyone. Write that down before an incident answers it for you.

When to build your own authentication

Three cases, narrower than any pro-building post admits and wider than the zero the vendor posts imply.

Authentication is the product. You sell identity, a wallet, a credential issuer. The login journey is the differentiated surface rather than the door to it, and buying means outsourcing your core.

The identity assertion is not OIDC- or SAML-shaped.A smartcard, a national eID scheme, a device-bound attestation, a thirty-year-old directory with its own protocol. Off-the-shelf servers assume an email address and a standards-based assertion. When it’s something else you write the adapter regardless, and sometimes the adapter is most of the system.

An accreditation regime where the third-party dependency costs more than the build.Some defence and government contexts. If you’re in one you already know, because a compliance officer told you rather than a blog post.

Notice what isn’t on that list: scale. At ten million MAU the per-user line genuinely does dominate, but the answer there is self-hosting. That’s the flaw in the standard cost-of-rolling-your-own-auth argument. It compares building to buying and omits the option that wins.

Using Auth.js with a credentials provider is building

This is where most teams end up by accident. Auth.js, formerly NextAuth, is excellent at what it does, which is wiring OAuth providers into a session in a Next.js app. Add a credentials provider and you’ve taken ownership of password hashing, reset-token lifetimes, email verification, MFA enrolment, session revocation across devices and account linking. That’s the build option wearing a library’s name.

If you do it anyway: Argon2id at or above the OWASP minimum parameters, refresh tokens that rotate with reuse detection, reset tokens that are single-use, short-lived and compared in constant time, and a hard rule that a social login never merges into an existing account on an unverified email address. That last one is the most commonly shipped vulnerability in hand-rolled auth, and it’s a complete account takeover rather than a finding.

The migration cost of being wrong

This is the section vendor comparisons skip, and it determines how expensive a wrong choice actually is. The answer isn’t “swap the SDK.”

Password hashes travel badly

Some providers export hashes and some import them; the pairing has to work in both directions and in the same algorithm family. Where it doesn’t, your only route is lazy migration: run both systems, verify each login against the old one, rehash into the new, and force a reset on whoever is left at the end of the window. The share who never return in that window isn’t a mystery figure. It’s your monthly-actives-over-total ratio, measurable this afternoon.

The vendor user ID is a foreign key across your whole company

By the time you want to leave, the provider’s subject identifier is stamped on your rows, your event stream, your billing metadata, your support tool and your logs. Migrating means either preserving those identifiers, which is usually impossible, or maintaining a mapping table forever.

One column of insurance, and the cheapest advice in this article: never make the vendor’s ID your primary key. Mint your own UUID per user, store the vendor subject as a nullable unique column beside it, and join through your own identifier everywhere else. On day one that costs an hour. Retrofitting it later is the same class of work as deciding whether to rewrite or refactor a codebase you inherited.

Sessions, MFA and social identities do not come with you

Sessions and refresh tokens are signed by keys the old provider holds, so cutover logs everyone out. On the web that’s an annoyance. On mobile, where refresh tokens are long-lived and reinstalls are rare, it’s a support spike and a run of one-star reviews. Put it in a release plan, not a Friday deploy.

TOTP secrets are generally not exportable, so every user with 2FA re-enrols and your recovery-code flow carries more traffic that day than it will ever see again. Test it first. And social identities are keyed on the provider’s stable subject rather than on email, because emails change and subjects don’t. Re-keying on email during a migration either merges two accounts that should be separate or splits one that shouldn’t be. Both are worse than being logged out.

What we would actually pick, by product shape

Consumer product, Next.js, under 50,000 MAU, no enterprise buyers.Buy. Clerk for the prebuilt components and the speed, Supabase Auth if you’re already on Postgres and want row-level security keyed to the same identity. We build on the latter, which is a bias we should state rather than bury: our Supabase engineering work means we’re fluent in it, not that this is neutral advice.

B2B SaaS below roughly five enterprise connections. Buy, and read the connection pricing before you sign. Model the invoice at three times your current enterprise customer count.

B2B SaaS above roughly ten connections, or with data residency constraints. Self-host Keycloak or Ory, and staff it properly. In regulated work residency usually decides this before the arithmetic does, a pattern across fintech and payments engineering, where which jurisdiction holds the identity data is a compliance answer rather than a preference.

Anything else. Buy, and spend the saved weeks on the part of the product a customer would pay for.

When you should not hire us, or anybody

If you’re a Next.js product with consumer-shaped authentication and no enterprise SSO requirement, integrating Clerk or Supabase Auth is a two-day job for one competent developer and you shouldn’t pay an agency for it. The quickstarts work. The middleware is a few dozen lines. Pay for this and you’re paying a markup on reading documentation.

There’s a tell in the market that supports this: search for an agency specialising in authentication implementation and you won’t find one, because the vendors made the happy path too easy to bill for. That’s a real limit on what a studio like ours can honestly claim here.

Where outside help does earn its cost: migrating off a provider without logging out a paying user base, standing up a self-hosted identity server that has to survive an audit, building an SSO onboarding flow your customers’ IT teams can finish without you on a call, and untangling a hand-rolled system four years into production. Those are operations problems rather than login-form problems. If yours is one of them, describe it to us in a paragraphand we’ll tell you whether it needs anyone at all.

The compressed decision

Buy for consumer-shaped authentication, because at 10,000 MAU almost every provider is free and your time isn’t. Count enterprise SSO connections rather than users, because that’s the line that grows. Self-host a maintained identity server when connection pricing becomes your largest infrastructure cost or residency removes the choice, and give it a named owner and an upgrade schedule the day it ships. Build only if identity is your product, your assertion isn’t standards-shaped, or accreditation forces it.

And whichever you pick, mint your own user IDs. The point of that column is that being wrong stays cheap.

Got a version of this problem?

Send a paragraph describing what you’re trying to build and what’s currently in the way. We reply inside two working days with a scope, a price and a start date. If we’re not the right people for it, we say that instead.