ContentForger

Guides

Web App Authentication: Passwords, Magic Links, OAuth and Passkeys

Web app authentication compared: how passwords, magic links, OAuth and passkeys work, what each costs to run safely, and a sensible default.

By Thomas Lovas Lokoy — 2026-10-17, last updated 2026-10-17

A bunch of keys on a keyring
Photo: Keys by walknboston · CC BY 2.0 · cropped
On this page (9)
  1. How web app authentication works, in one paragraph
  2. Passwords
  3. Magic links and email codes
  4. OAuth and "Sign in with Google"
  5. Passkeys
  6. Comparing the four
  7. The session rules that apply to all of them
  8. A sensible default for a first app
  9. Sources

Web app authentication is the first feature that can hurt real people if you get it wrong. A broken layout annoys users; a broken login hands their data to someone else. If you are building your first web app, you will choose between four common login methods: passwords, magic links, OAuth ("Sign in with Google"), and passkeys. This guide explains how each one works, what it costs you to run safely, and how to pick a sensible default.

How web app authentication works, in one paragraph

Every method proves that the person at the keyboard owns the account. Once they do, your server creates a session, usually a random identifier in a cookie, and checks it on every request. Only the proof differs, so the session rules near the end apply to all four.

Passwords

The user picks a secret, you store a slow hash of it, and you compare hashes at login. Passwords are familiar and need no third party, but they put the most work on you.

The OWASP Authentication Cheat Sheet sets the current baseline. Without multi-factor authentication, it says "passwords shorter than 15 characters are considered to be weak"; with MFA enabled, the floor drops to 8 characters. It also says "Maximum password length should be at least 64 characters to allow passphrases" and "There should be no password composition rules limiting the type of characters permitted." In other words, drop the "one uppercase, one symbol" rule and allow long passphrases.

Three more OWASP rules are easy to miss:

  • Block breached passwords. The cheat sheet says to "Block common and previously breached passwords," and points to the Pwned Passwords service as one way to check.
  • Use generic errors. A failed login should not reveal whether the account exists. OWASP's example message is "Login failed; Invalid user ID or password." Response time and status codes should also be the same for both cases.
  • Do not force regular password changes. OWASP advises: "Avoid requiring periodic password changes." Force a change only when a leak is suspected.

Storage is where self-built password systems usually fail. The OWASP Password Storage Cheat Sheet recommends: "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism." If you inherit bcrypt, use "a work factor of 10 or more" and note that bcrypt has a 72-byte input limit.

Passwords also need a reset flow, and that flow is a login method in its own right. The OWASP Forgot Password Cheat Sheet says reset tokens must be "Randomly generated using a cryptographically safe algorithm," "Single use and expire after an appropriate period," and the reset page should return "a consistent message for both existent and non-existent accounts." If you build passwords, you are building this too.

Choose passwords when your users cannot rely on email access at login time, or you are adding login to an existing system that already has them. Pair them with MFA where you can: OWASP calls MFA "by far the best defense against the majority of password-related attacks."

The user enters an email address, you send a link (or a short code), and clicking the link signs them in. There is no password to store, forget or reuse across sites.

A magic link is really the password-reset flow used as the main login, so the same token rules apply: random, single-use, short-lived, rate-limited. Supabase's documentation gives a concrete example of default settings: "By default, a user can only request a magic link once every 60 seconds and they expire after 1 hour." The same page notes that the email code variant has users "key in a six-digit code sent to their email address," and that "If the user hasn't signed up yet, they are automatically signed up by default." That last default suits a consumer app but may not suit an invite-only tool, so check it.

Downsides worth knowing before you commit:

  • The user's inbox becomes the account. Anyone who can read their email can sign in.
  • Delivery is now part of login. Slow or spam-filtered email means a failed login.
  • Device switching is awkward. A user who requests a link on a laptop and opens it on a phone can end up signed in on the wrong device. Email codes avoid this because the user types the code where they started.

Choose magic links or email codes when people log in rarely (a booking tool, a monthly report) and you would rather not run a password system.

OAuth and "Sign in with Google"

The user clicks a provider button, signs in with the provider, and the provider sends them back to your app with proof of identity. You never see their password. Strictly, OAuth handles authorization and OpenID Connect (built on top of it) handles login. The OWASP Authentication Cheat Sheet says it plainly: "OAuth is an authorization framework for delegated access to APIs."

The OWASP OAuth 2.0 Cheat Sheet is the reference for doing this safely. Its main points for a small app:

  • Use the authorization code flow with PKCE. The old implicit flow is "deprecated by RFC 9700" and "removed from OAuth 2.1" because it puts tokens in the URL. PKCE means "the attacker cannot redeem a stolen authorization code at the token endpoint."
  • Protect the callback against CSRF, either through PKCE or with one-time values carried in the state parameter.
  • Link accounts by the provider's stable identifier, not by email. OWASP's authentication guidance says to identify linked accounts by the issuer and subject claims in the ID token, and to validate that token's issuer, audience, signature and expiry.

Choose OAuth when your users already live in Google, Microsoft or GitHub, such as a tool for a team or for developers. Expect to offer a second method too, because not everyone wants to link an account.

Passkeys

A passkey is a key pair. The private key stays on the user's device or in their password manager, and your server stores only the public key. Login is a fingerprint, face scan or device PIN. The FIDO Alliance defines it as "an authentication credential based on FIDO standards," and passkeys.dev puts it simply: passkeys are "a replacement for passwords."

Their main advantage is phishing resistance. As passkeys.dev explains, "browsers and operating systems enforce that passkeys are only ever used for the appropriate service," so a lookalike domain cannot collect a working credential. The FIDO Alliance says passkeys "are designed so that there are no shared secrets." Because, in the words of passkeys.dev, "Relying Party (RP) servers store public keys," a database leak does not expose anything an attacker can log in with.

Two variants exist. "Synced passkeys" are copied between a user's devices through a cloud service; device-bound passkeys "never leave a single device," such as those on hardware security keys. OWASP adds a caution here: "Relying parties should not assume that keys are hardware-backed and non-exportable unless this is verified."

The practical gap is recovery. A user who loses every device that holds a passkey still needs a way back in, which usually means email or a second passkey registered in advance. Plan that path before you launch passkeys.

Choose passkeys when you can offer them alongside a fallback. They are strong as a second option you encourage users to adopt, and increasingly reasonable as the primary one.

Comparing the four

MethodWhat you storeMain riskExtra work for you
PasswordsSlow password hashReuse, phishing, weak storageHashing, breach checks, reset flow, lockout
Magic link or codeShort-lived tokenInbox compromise, email deliveryEmail sending, rate limits
OAuth / OIDCProvider subject IDMisconfigured callback, account linking by emailProvider setup per provider
PasskeysPublic keyAccount recoveryFallback method, device prompts

The session rules that apply to all of them

Whatever proves identity, the session cookie that follows is what attackers target. The OWASP Session Management Cheat Sheet lists the baseline:

  • Set the Secure and HttpOnly attributes on the session cookie. OWASP calls HttpOnly "mandatory to prevent session ID stealing through XSS attacks."
  • Set SameSite to Strict or Lax explicitly: "do not rely on the browser-default value."
  • Generate session IDs with a cryptographically secure random generator; OWASP gives "at least 64 bits of entropy" as the floor.
  • Regenerate the session ID after login. OWASP calls this "mandatory to prevent session fixation attacks."
  • Pick timeouts to match your risk. OWASP's examples are 15 to 30 minutes idle for low-risk apps and 2 to 5 minutes for high-value ones.

A sensible default for a first app

Do not write your own authentication if you can avoid it. Use an established auth library or a hosted auth service, and spend your time checking its settings against the rules above. For most first apps, a good starting point is email codes or magic links plus one OAuth provider your audience already uses, with passkeys added once the basics are stable. Add passwords only if you have a concrete reason, because they bring the most work and the most risk.

If you are using Supabase, the walkthrough in Supabase Auth in your ContentForger app covers the setup steps. Then test login, logout and wrong-user access with the pre-launch checklist before anyone else signs up.

Sources

ShareXLinkedInFacebook

Was this article helpful?

New guides in your inbox

One short email when we publish something useful — tutorials, comparisons and launch checklists. Unsubscribe in one click.

Related articles