On this page
  1. The six questions that decide this
  2. The realistic options, compared
  3. Sessions versus JWTs, specifically
  4. Adding a provider: OAuth, OIDC, and passkeys
  5. Selling to companies: SSO changes the shape of the problem
  6. Checklist
  7. FAQ
    1. Which authentication method should a new app start with?
    2. Do I need OAuth if I am not offering social login?
    3. Are passkeys ready for production?
    4. How should I authenticate API clients and service accounts?
  8. Related topics
  9. Sources
comparison

How to Choose an Authentication Method for Your App: A Decision Guide

Sessions, JWTs, OAuth, passkeys, magic links, or SSO — the six questions that decide your auth method, a comparison table, and the cases where each option is the wrong pick.

Quick answer

  • Default to server-side sessions with a password and a second factor. It’s the option with the fewest ways to be wrong, and it gives you logout and instant revocation for free.
  • Six questions decide it: who your users are, whether you need instant revocation, how many services verify the caller, whether there’s a mobile client, what compliance requires, and whether your users can be phished.
  • JWTs earn their complexity when several services must verify a caller without a shared session store. Otherwise sessions are simpler and safer.
  • Add OAuth when you want users to skip creating a password; add passkeys when phishing resistance is the priority.
  • Never authenticate machines with user credentials — give each service its own scoped identity.
  • The comparison table below is the reference; the questions above it are how you pick a row.

The six questions that decide this

Authentication choices get argued as preferences. They’re actually decided by constraints, and these six narrow the field faster than any feature list:

  1. Who are your users — consumers or companies? Companies often require their own identity provider, which means SAML or OIDC federation rather than a local password.
  2. Do you need to revoke a session instantly? “Log out everywhere after a password change” and “kill the session of a compromised account” are trivial with server-side sessions and require extra machinery with stateless tokens.
  3. How many services verify the caller? One app can share a session store. Five services that can’t reach each other’s sessions are the case JWTs were built for.
  4. Is there a mobile or native client? Cookies work in browsers; native apps need a token they can store securely in the platform keystore.
  5. Does anything require a second factor or a specific factor type? Compliance regimes and enterprise customers often mandate MFA and sometimes phishing-resistant MFA specifically.
  6. Can your users be phished? Anyone can, which is the argument for passkeys — the credential is bound to your origin and won’t be replayed on a lookalike domain.

Answer those and the shortlist is usually obvious. The table below is the reference for choosing between what’s left.


The realistic options, compared

Server-side sessionsJWTOAuth / OIDCPasskeys (WebAuthn)Magic link / email OTPEnterprise SSO (SAML / OIDC)
How it worksOpaque session ID in a cookie; state lives on the serverSigned token the client presents; state lives in the tokenA provider authenticates the user and returns a token about themPublic-key credential bound to your domain, unlocked by the deviceA single-use link or code proves control of an inboxThe customer’s IdP authenticates, your app consumes an assertion
Best forA normal web app with a browser front endMultiple services verifying a caller without shared stateConsumer apps that want fewer passwordsPhishing resistance, app-based sign-in, passwordlessFrictionless onboarding, low-stakes accountsSelling to companies with existing identity systems
RevocationImmediate — delete the sessionHard — you need a denylist or short expiryProvider-dependent, plus your own sessionRemove the credential from the accountExpiry is the only control, so keep it shortDepends on the IdP’s session
ComplexityLowestMedium, and easy to get wrongMedium — redirects, state, token validationLow for the flow, higher for recoveryLowHigh — metadata, certificates, mapping
Main riskSession fixation, CSRFSignature verification mistakes, no expiryOpen redirect, unverified token audienceAccount recovery after a lost deviceLink interception and email account compromiseMis-mapped attributes granting wrong access
Wrong whenYou have several services that can’t share a session storeYou only have one app and no revocation storyYou need offline or machine-to-machine accessYou haven’t designed account recoveryThe account controls anything valuableYour users are individuals, not organizations

Read the last row first — every method here is correct for a set of constraints and a poor fit outside them.


Sessions versus JWTs, specifically

This is the most common fork, and it’s usually decided on popularity rather than requirements. Server-side sessions keep the truth on the server: the cookie holds an opaque identifier, and deleting the row ends the session immediately. That gives you logout, admin-forced logout, and password-change invalidation with no extra code.

JWTs move the truth into the token. Any service holding the signing key can verify a caller without a database lookup, which is genuinely valuable when services don’t share storage. The cost is that a token remains valid until it expires unless you maintain a revocation list — which is the state you were trying to avoid.

The practical rule: one app with a browser front end → sessions. Several services that must verify callers independently → JWTs, with short expiries and a refresh mechanism you’ve actually implemented. Whichever you choose, the mistakes cluster in the same places.


Adding a provider: OAuth, OIDC, and passkeys

OAuth is not an authentication protocol — it’s a delegation protocol for access, and OpenID Connect layers identity on top. In practice you adopt it for one of two reasons: users don’t want another password, or you don’t want to store credentials, resets, and MFA enrollment yourself.

Passkeys are the other adoption path, and the case is different: they remove the phishing vector rather than the password. The credential is a key pair bound to your domain, so a credential stolen from a convincing lookalike site is useless. The design work is in recovery, not the login flow.


Selling to companies: SSO changes the shape of the problem

If a customer’s IT department asks how their employees sign in, the answer needs to be their identity provider, not your password form. SAML and OIDC federation move authentication to the customer and hand you an assertion you map to a local account.

This is a sales-driven requirement rather than a technical preference, and it brings its own failure modes: attribute mapping that grants the wrong role, certificate rotation that breaks logins silently, and provisioning that never happens automatically. Budget for it once, not per customer.


Where this bites vibecoders

Ask an assistant for “add authentication” and the answer is shaped by frequency in its training data, which is JWT plus a password hash in a users table — regardless of whether you have one service or six, a mobile client, or any need to verify callers without shared state. The result usually works, which is the problem: you inherit a revocation gap (logout that doesn’t invalidate, sessions that outlive a password change) that you only notice during an incident, when you need to force someone out of their account and discover you can’t. The fix isn’t a different token format; it’s deciding the revocation story before choosing the method, and stating your constraints — number of services, client types, whether logout must be immediate — in the prompt rather than asking for “auth.”

Checklist

  • Write down your constraints — users, clients, services, revocation, compliance — before picking a method.
  • Default to server-side sessions for a single web app.
  • Use JWTs only when several services must verify callers independently.
  • Give tokens short expiries and implement the refresh path, or don’t use them.
  • Hash passwords with a slow, salted algorithm; never store them reversibly.
  • Put a rate limit and lockout on login, reset, and MFA endpoints.
  • Design account recovery before enabling passkeys.
  • Authenticate machines with their own scoped credentials, never a user session.
  • Test the revocation path: change a password and confirm existing sessions die.

FAQ

Which authentication method should a new app start with?

Server-side sessions with a password and a second factor. Sessions give you logout, expiry, and instant revocation for free, the browser handles the credential transport, and there is no token format to get wrong. Reach for JWTs when multiple services need to verify a caller independently, and add OAuth when you want users to skip creating a password at all.

Do I need OAuth if I am not offering social login?

No, but you may want OpenID Connect for a different reason: it moves password handling to someone else. If you don’t want to store credentials, reset flows, and MFA enrollment yourself, delegating sign-in to a provider removes an entire category of risk. What you take on instead is dependency on that provider’s availability and a mapping between their identity and your user records.

Are passkeys ready for production?

Yes, as an additional option rather than a replacement. Every major browser and platform supports WebAuthn, and the flow is phishing-resistant by construction because the credential is bound to your domain. The practical caveats are account recovery — losing the device must not mean losing the account — and users who expect a password field to exist.

How should I authenticate API clients and service accounts?

Not with a user session. Use scoped credentials issued per consumer: an API key with a defined scope for a trusted server-to-server integration, or OAuth client credentials for a third party. Store them hashed where possible, rotate them on a schedule, and treat each one as a non-human identity with the minimum access its job requires.


Sources

Share: