Need the #1 custom application developer in Brisbane?Click here →

Security

Authentication Patterns

10 min readLast reviewed: March 2026

Authentication is the process of verifying that users are who they claim to be. Choosing the right authentication pattern is fundamental to your application's security, scalability, and user experience. This guide explores the most common patterns and when to use each one.

Session-Based Authentication

Session-based authentication is the traditional approach used by server-rendered applications for decades. When a user logs in, the server creates a session object that stores user information in memory or a database, then returns a session ID to the client via an HTTP cookie.

How it works: The browser automatically includes the session cookie with every request. The server looks up the session ID, validates it's not expired, and grants access. When the user logs out, the session is destroyed on the server.

Session Cookie Security
Cookies should always have the HttpOnly flag set, preventing JavaScript access and protecting against XSS attacks. The Secure flag ensures transmission only over HTTPS. The SameSite attribute prevents CSRF attacks by restricting cross-site cookie sending.

When to Use Sessions

Sessions are ideal for traditional server-rendered web applications where the backend renders HTML. They work naturally with form submissions and server-side state management. Sessions are also excellent for applications that need to revoke access immediately—you simply delete the session, and the user is logged out on their next request.

Token-Based Authentication (JWTs)

Token-based authentication, particularly JSON Web Tokens (JWTs), is a stateless approach where the server doesn't store session information. Instead, the server signs a token containing user claims and sends it to the client. The client includes this token with every request, and the server validates the signature to confirm it hasn't been tampered with.

The token flow: Client logs in → Server issues signed token → Client stores token → Client sends token with requests → Server validates signature and processes request.

Token Storage Trade-offs
JWTs can be stored in localStorage (vulnerable to XSS) or httpOnly cookies (more secure). Many modern applications use a hybrid approach: an httpOnly refresh token stored in a cookie and a short-lived access token in memory or localStorage. This balances security and usability.

When to Use JWTs

JWTs shine in Single Page Applications (SPAs), mobile apps, and microservices architectures. Because they're stateless, you don't need a session store, making horizontal scaling simple. Each server can independently validate the token without asking a central database.

Authentication Flows

Different authentication flows serve different use cases. Understanding each helps you choose the right tool for your situation.

Login Form Flow

The simplest pattern: user enters email/password, server validates credentials against a hashed password in the database, and issues a session or token. This is the foundation of authentication in most web apps. The main security challenge is protecting the password—it must be hashed, never stored plaintext, and transmitted only over HTTPS.

OAuth Redirect Flow

Rather than managing passwords yourself, delegate authentication to a trusted provider like Google or GitHub. The user is redirected to the provider, authenticates there, and returns to your app with a token. Your app uses that token to fetch the user's profile. This eliminates the burden of storing passwords and offloads account recovery to the provider.

Magic Link Flow

A user enters their email, you send them a time-limited link containing a unique token, and clicking the link logs them in automatically. Magic links eliminate the password problem entirely—no weak passwords, no password reuse. They work well for apps with infrequent users (content publishing, survey tools) but can feel slow for daily-use applications.

Passkey Flow

Passkeys are cryptographic credentials stored on a device (phone, laptop) that replace passwords. When the user authenticates, the device signs a challenge without sending any secret. This is phishing-resistant because the credential is device-bound, and impossible for an attacker to steal remotely. Passkeys are the future but require device enrollment.

Stateful vs Stateless Trade-offs

Sessions store state on the server; tokens carry state to the client. Choose based on your architecture and requirements.
AspectSessions (Stateful)Tokens (Stateless)
Server StorageRequired (memory or DB)Not needed
RevocationImmediateOnly at token expiry
ScalingRequires session storeScales horizontally
Token SizeSmall (just ID)Large (contains claims)
DeploymentSingle server or clusterAny number of servers
RefreshImplicit on page loadExplicit refresh token flow
Best forServer-rendered appsSPAs, mobile, microservices
Hybrid Approach
Many modern apps use both: sessions for traditional server-rendered pages and token-based auth for API endpoints. This gives you the best of both worlds—simple session management for traditional flows and scalable token auth for distributed APIs.

Multi-Factor Authentication (MFA)

Multi-factor authentication adds a second verification step beyond the password. The three categories are:

Something you know: A security question or PIN.

Something you have: A physical device like a security key or a phone that receives a code via SMS or an authenticator app.

Something you are: Biometrics like a fingerprint or face recognition.

Implementing MFA in your authentication flow adds a prompt after password verification. The user proves they have the second factor, and only then is the session or token issued. Time-based one-time passwords (TOTP) using apps like Google Authenticator or Authy are the gold standard—they're not vulnerable to SMS interception like SMS OTPs.

Remember Me and Persistent Login

Users often want to stay logged in across browser restarts. A "Remember Me" checkbox typically extends the session or token lifetime. The security cost is significant—a stolen session or token now grants access for months instead of hours.

The safer pattern is a persistent refresh token stored in an httpOnly cookie with a long expiration (weeks or months) alongside a short-lived access token (minutes). If the access token is compromised, damage is limited to that short window. If the refresh token is compromised, the attacker can issue themselves new access tokens, but you can invalidate the refresh token immediately.

Session Expiry and Refresh Strategies

Sessions shouldn't live forever. An expiry time limits the window an attacker has if they steal a session. Absolute expiry means the session expires after a fixed time (e.g., 8 hours) regardless of activity. Idle expiry means it expires only if unused for a period (e.g., 30 minutes).

For tokens, a refresh token rotation pattern is common: the access token expires quickly (15 minutes), and when it expires, the client uses the refresh token to get a new access token. If a refresh token is used to request a new access token and the old token is also used, you detect token theft and invalidate both. This is called refresh token rotation.

Refresh Token Rotation Pattern
When a client exchanges a refresh token for a new access token, issue a new refresh token as well and rotate out the old one. Store the issued refresh token families on the server. If you see a refresh token from a previous family being used, that indicates token theft—invalidate the entire family and force re-authentication.

Choosing the Right Pattern for Your App

Server-rendered web application (Next.js pages, Django, Rails): Use session-based authentication with httpOnly cookies. Sessions integrate naturally with server-side rendering and are well-understood.

Single Page Application (React, Vue, Angular): Use token-based auth with JWTs. Consider a hybrid approach with a refresh token in an httpOnly cookie and the access token in memory. This avoids the XSS vulnerability of storing sensitive tokens in localStorage.

Mobile app: Use token-based auth with secure token storage (Keychain on iOS, Keystore on Android). Implement certificate pinning to prevent man-in-the-middle attacks.

API consumed by multiple clients: Use OAuth 2.0 for delegated access, or API keys for service-to-service authentication. Each consumer type has different requirements—web apps, mobile apps, and backend services may each need different approaches.

Authentication is not a one-size-fits-all problem. The best pattern depends on your application architecture, how you deploy it, who your users are, and your security requirements. Start simple, implement the pattern correctly, and add complexity (like MFA or refresh token rotation) only where risk justifies it.