Engineering Journal
Ginexys
Ginexys

The Authentication Security Checklist: What Gets You Breached, What Protects You, and the Tradeoffs Nobody Talks About

2026-06-03

TLDR

Most production auth breaches are not caused by zero-day cryptographic exploits; they are caused by the exact same six failure modes repeated across thousands of web applications. Based on RFC 6749, RFC 7636, OWASP ASVS, and NIST SP 800-63B, this guide details the engineering checklist for securing client-side, edge, and native auth surfaces.
Security PillarPrimary Risk FactorRequired Engineering ControlHistorical High-Profile Failure
TransportCredentials leaked in URLs/logsAuthorization: Bearer headers + POST bodyGitHub (2020) URL token logging
Password HashingFast GPU offline brute forcingArgon2id / bcrypt (cost ≥ 12) / scryptLinkedIn (2012) SHA-1 unsalted leak
Session ControlZombie tokens surviving logoutServer Max-Age=0 cookie destructionFirebase 1-hour post-logout token validity
OAuth ProtectionAuth code interception / CSRFPKCE (RFC 7636) + Nonce state validationTwitter pre-2019 mobile code interception
Token StorageXSS token theft via localStorageHttpOnly SameSite=Lax cookies & OS KeychainAuth0 (2020) localStorage advisory

Standardized implementation flaws cause most web authentication breaches

Every major web application auth breach over the past decade traces back to one of six recurring implementation flaws:

  1. Credentials in wrong locations: Placing secrets in URL query parameters, server logs, git history, or client localStorage.
  2. Infinite token lifetimes: Issuing JWTs with exp: 2099 or omitting refresh token rotation.
  3. Unverified signatures: Accepting unverified JWTs or allowing alg: none header bypasses.
  4. OAuth protocol shortcuts: Skipping PKCE on public clients, omitting state validation, or allowing wildcard redirect_uri matches.
  5. Silent session inheritance: Failing to pass prompt=select_account on shared terminal screens.
  6. Missing defense in depth: Omitting Content Security Policies (CSP), rate limiting, and generic error messaging.

Edge-enforced boundaries block transport and storage exploits

           [Client Browser / SPA / Extension]
             /            |            \
            /             |             \
   [Bearer Tokens]  [HttpOnly Cookies]  [OS Keychain]
          |               |               |
          v               v               v
  [OAuth PKCE Flow]  [Edge Session]  [Store Secrets]
          \               |               /
           \              v              /
        +-----------------------------------+
        |  Cloudflare Edge / Supabase Identity|
        +-----------------------------------+

Credential transport without URL parameters

Never put credentials in URL query strings. URLs are written into browser histories, server access logs, CDN logs, proxy caches, and Referer headers.
// Transport via standard Authorization header
fetch('/api/resource', {
  headers: { Authorization: 'Bearer secret_123' }
});

Password hashing with memory-hard algorithms

Avoid fast hash algorithms like MD5, SHA-1, or plain SHA-256. A modern GPU cluster can compute over 10 billion SHA-256 hashes per second. Always enforce memory-hard functions like Argon2id or bcrypt (cost factor ≥ 12). Memory hardness forces the GPU bottleneck onto memory bandwidth rather than compute cores, reducing brute-force attempts by 3 to 4 orders of magnitude.

Session management and single-use token rotation

Deleting client-side tokens during logout does not invalidate a JWT on the server. If using short-lived access tokens (15 minutes or less), refresh tokens must implement single-use rotation and reuse detection:
// Server-side Refresh Rotation pseudo-logic
async function handleRefresh(oldRefreshToken) {
  if (await isTokenReused(oldRefreshToken)) {
    // REUSE DETECTED: Immediately revoke all tokens in session family!
    await revokeAllFamilySessions(oldRefreshToken);
    throw new SecurityError("Refresh token replay attack detected");
  }
  const newTokenPair = await issueNewTokenPair();
  await markTokenUsed(oldRefreshToken);
  return newTokenPair;
}

Protecting public clients with PKCE and state validation

Any browser SPA, mobile app, or VS Code webview extension that cannot hide a client secret must use PKCE (RFC 7636). The client generates a random code_verifier, derives a code_challenge, and sends the challenge with the initial auth request. The server verifies the code against the verifier during token exchange. Without the verifier, intercepted authorization codes are useless.

Always append prompt=select_account (Google) or prompt=login (GitHub) to prevent silent session inheritance on shared workstations.

Token storage in HttpOnly cookies and OS keychains

localStorage is accessible to any JavaScript running on the page, meaning an XSS vulnerability translates directly into token theft. HttpOnly cookies cannot be read or modified by JavaScript, effectively blocking script-based exfiltration.

For native extensions (such as VS Code plugins), store credentials strictly inside OS Keychain services via vscode.ExtensionContext.secrets.store().

Defense in depth with CSP and per-account rate limits

Deploy strict Content Security Policies on all auth surfaces to prevent script injection:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; connect-src 'self' https://auth.ginexys.com; frame-ancestors 'none';

Rate limiting must operate on a per-account basis in addition to per-IP checks, utilizing soft lockouts (delays, CAPTCHAs) rather than hard account lockouts to prevent denial-of-service abuse.


Invariant enforcement secures multi-client architectures

Rule of thumb: Auth security is not about inventing novel cryptography. It is about rigorously enforcing established RFC invariants across every public, private, and secondary code path in your system.
Read this post in the full Engineering Journal →