There are two ways founders get authentication wrong, and they end in the same place. The first is rolling your own — hand-built session handling, a homegrown password reset flow, custom token logic — because a provider felt like overkill. The second is bolting on a provider and configuring it badly — tokens that never expire, no MFA, the entire user table exposed because the integration was copied from a quickstart and never hardened.
Both produce the same outcome: an authentication layer that an attacker walks through. Auth is the front door to everything. Get it wrong and nothing behind it matters.
What a broken front door costs
Credential-based attacks are the most common initial-access vector in breach reporting, and authentication failures sit near the top of the OWASP list for a reason. The cost isn't abstract: a credential-stuffing run against a login endpoint with no rate limiting can validate thousands of leaked password pairs against your users in an afternoon, and every hit is an account takeover. For a B2B product, one taken-over admin account is access to that customer's entire workspace — and a disclosable incident.
The asymmetry here is brutal. Authentication is a solved problem with mature, battle-tested solutions. The cost of getting it right is mostly the cost of deciding to use them instead of improvising. The cost of getting it wrong is account takeover at scale.
Session vs token: pick on purpose
The first architectural decision is how you maintain "this user is logged in" across requests. There are two models and teams routinely choose by accident.
Session-based: the server creates a session, stores it server-side, and hands the client an opaque session ID in a cookie. Every request, the server looks up the session. The advantage: you can revoke instantly — delete the session, the user is logged out everywhere, immediately. The cost: a session store the server has to check on every request.
Token-based (JWT): the server signs a token containing the user's claims and hands it over. The client sends it back; the server verifies the signature without a lookup. The advantage: stateless, scales horizontally with no shared session store. The cost — and it's the one people forget — you cannot easily revoke a valid token before it expires. A stolen JWT works until expiry, no matter what.
session → revocable instantly, needs server-side store
token → stateless & scalable, can't be revoked mid-life
The footgun is choosing tokens for scalability, setting a long expiry for convenience, and then discovering you have no way to log out a compromised account. The standard correct pattern: short-lived access tokens (minutes) plus a revocable refresh token (server-side, long-lived). You get stateless verification on the hot path and real revocation through the refresh token. Most teams that "use JWTs" implement only the first half and ship a system they can't revoke.
MFA, and making it stick
A password is a single factor and single factors fall to phishing, reuse, and stuffing. MFA — a second factor — is the highest-impact control you can add to authentication, and it stops the overwhelming majority of credential-based attacks outright.
But MFA only works if it's used. Optional MFA that 4% of users enable protects 4% of users. The pattern that works: require MFA for anything privileged — admin accounts, anything touching billing or other users' data — and strongly default it on for everyone else. For enterprise customers, the answer is usually SSO, which moves the MFA requirement to their identity provider where it's already enforced.
On the factor itself: TOTP (an authenticator app) is solid and phishing-resistant enough for most products. SMS is better than nothing and worse than everything else — SIM-swap attacks make it the weakest second factor, so don't make it the only option. Which leads to the better answer.
Passkeys: the actual upgrade
Passkeys (built on WebAuthn) are the first authentication primitive in years that is both more secure and easier for the user. A passkey is a cryptographic key pair bound to the user's device and the specific site. There's no shared secret to steal, nothing to phish, and nothing in a database breach worth taking — the server only ever holds a public key.
Passkeys are phishing-proof by construction: the credential is bound to your real domain, so a lookalike phishing site can't elicit it. They eliminate the password reset flow, which is one of the most commonly broken parts of any auth system. And users tap a fingerprint sensor instead of typing a password.
The honest tradeoff: passkey UX around device loss and account recovery still requires careful design, and not every user base is ready to go passwordless. The senior move is to support passkeys as a first-class option now, alongside password+MFA, and let adoption grow. You don't have to choose passwordless-only to get most of the benefit.
SSO: the enterprise gate
The moment you sell to enterprises, SSO stops being optional. Enterprise security teams require that their employees authenticate through the company identity provider — Okta, Entra, Google Workspace — over SAML or OIDC. No SSO, no deal, and "SSO is on the roadmap" loses the contract.
SSO is also a security win you're being handed: it moves credential management, MFA enforcement, and offboarding to the customer's IdP. When their employee leaves, their IdP cuts access and your app is covered automatically — no orphaned account waiting to be abused.
Build SSO as a proper integration, not a checkbox. Support both SAML and OIDC, because enterprises split between them. Map IdP groups to your roles so access provisioning flows from their directory. And — the part teams botch — handle just-in-time provisioning and deprovisioning correctly, so a user removed in the IdP actually loses access in your app rather than lingering. This connects directly to the access-control and audit work in enterprise SSO, RBAC, and audit logs from day one.
Build vs buy
The default should be buy. Authentication is undifferentiated, security-critical, and full of subtle requirements that a provider has already solved and continuously maintains. A managed auth provider gives you sessions, token handling, MFA, passkeys, SSO, and the security patches — for a price that is always lower than the engineering time to build and maintain the equivalent, let alone the cost of getting it wrong.
build your own auth: you now maintain a security product, forever
buy a provider: you integrate, configure correctly, move on
Buy when authentication is not your product, which is nearly always. The narrow case for building is when auth is the product, or when a hard requirement no provider meets forces your hand — and even then you build on vetted libraries, never raw crypto. What you never do is roll your own password hashing, your own token signing, or your own session crypto. Those are solved, and your version will be worse.
The bolt-on failure mode is real too, though: buying a provider doesn't excuse you from configuring it. The default settings are a starting point, not a finished posture.
The footguns, named
The implementation mistakes that recur, so you can check for them directly:
- Tokens that never expire. A stolen token is then permanent. Short access tokens, revocable refresh tokens.
- No rate limiting on login or reset. Credential stuffing runs free. Rate limit by IP and by account.
- Password reset that leaks account existence. "No account with that email" tells an attacker exactly which emails to target. Return the same response either way.
- MFA bypass paths. A reset flow or legacy endpoint that skips the second factor defeats the second factor.
- Storing session tokens accessibly. Tokens in localStorage are readable by any XSS; use httpOnly cookies.
- No revocation path. If you can't force-log-out a compromised account, you can't respond to a compromise.
What fixed looks like
You're on a vetted auth provider or a vetted library, never hand-rolled crypto. Your session model is a deliberate choice — short-lived access tokens with revocable refresh tokens, or server-side sessions — and you can force a logout when you need to. MFA is required for privileged accounts and defaulted on everywhere else. Passkeys are offered as a first-class option. SSO over SAML and OIDC is a real integration with working JIT deprovisioning, so enterprise prospects clear the security review instead of stalling on it.
Login and reset endpoints are rate-limited and don't leak which accounts exist. Tokens live in httpOnly cookies. Every footgun above has been checked and closed. When an enterprise security questionnaire asks how you authenticate, you answer with a system, not a hope.
This is for you if
You're a funded B2B company whose authentication grew up by improvisation — rolled by hand, or a provider dropped in from a quickstart and never hardened — and you're now selling to customers who'll audit exactly this. You want it built right before an account takeover or a lost enterprise deal forces the issue.
This is build and hardening work starting around $50k for an authentication overhaul on an existing product, and a designed-in part of larger build engagements ($100k+).
It's not for pre-product teams who should just adopt a provider's defaults and keep shipping, and it's not for anyone whose actual goal is to keep their hand-rolled auth and have someone bless it. The recommendation there is the same as the article: stop maintaining a security product you didn't mean to build.