Authentication verifies who users are. Authorization determines what they can access. This guide covers implementation approaches with security best practices from official documentation and OWASP guidelines.

Authentication Methods Overview

MethodBest ForComplexity
Session-basedTraditional web appsLow
JWT (stateless)APIs, microservicesMedium
OAuth 2.0Third-party loginMedium-High
PasswordlessModern UXMedium
Multi-factor (MFA)High securityMedium

Session-Based Authentication

The traditional approach: server stores session data, client holds session ID.

How It Works

  1. User submits credentials
  2. Server validates and creates session
  3. Session ID stored in HTTP-only cookie
  4. Client sends cookie with each request
  5. Server looks up session to identify user

Implementation Flow

Client                          Server
  |                               |
  |-- POST /login (credentials) ->|
  |                               |-- Validate credentials
  |                               |-- Create session in store
  |<-- Set-Cookie: sessionId -----|
  |                               |
  |-- GET /dashboard (cookie) --->|
  |                               |-- Look up session
  |                               |-- Return user data
  |<-- 200 OK (user data) --------|

Session Storage Options

StorageProsCons
MemorySimple, fastLost on restart, no scaling
RedisFast, scalableAdditional infrastructure
DatabasePersistent, simpleSlower than Redis
FileSimpleNo horizontal scaling

Security Requirements

Per OWASP Session Management guidelines:1

Cookie Settings:

  • HttpOnly - Prevents JavaScript access (XSS protection)
  • Secure - HTTPS only
  • SameSite=Lax or Strict - CSRF protection
  • Short expiration - Limit exposure window

Session ID Requirements:

  • Minimum 128 bits of entropy
  • Cryptographically random
  • Regenerate on login (prevent fixation)

Example: Express.js Session

const session = require('express-session');
const RedisStore = require('connect-redis').default;
const redis = require('redis');

const redisClient = redis.createClient();

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,        // HTTPS only
    httpOnly: true,      // No JS access
    sameSite: 'lax',     // CSRF protection
    maxAge: 1000 * 60 * 60 * 24  // 24 hours
  }
}));

Pros and Cons

Advantages:

  • Simple to implement
  • Easy session invalidation (delete from store)
  • Works with any client
  • Proven, well-understood

Disadvantages:

  • Server must store sessions
  • Requires session store for scaling
  • Not ideal for mobile apps or APIs

JSON Web Tokens (JWT)

JWTs are self-contained tokens that encode user information.2

JWT Structure

A JWT has three parts, base64-encoded and separated by dots:

header.payload.signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Header: Algorithm and token type

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload: Claims (user data)

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "exp": 1516242622
}

Signature: Verifies integrity

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

Standard Claims

Per RFC 7519:2

ClaimNamePurpose
issIssuerWho created the token
subSubjectWho the token is about (user ID)
audAudienceWho should accept it
expExpirationWhen it expires (Unix timestamp)
iatIssued AtWhen it was created
nbfNot BeforeWhen it becomes valid
jtiJWT IDUnique identifier

JWT Authentication Flow

Client                          Server
  |                               |
  |-- POST /login (credentials) ->|
  |                               |-- Validate credentials
  |                               |-- Generate JWT
  |<-- { token: "eyJ..." } -------|
  |                               |
  |-- GET /api (Authorization: Bearer token) -->|
  |                               |-- Verify JWT signature
  |                               |-- Check expiration
  |                               |-- Extract user from payload
  |<-- 200 OK (data) -------------|

Where to Store JWTs

StorageXSS SafeCSRF SafeNotes
HttpOnly CookieYesNeed SameSiteRecommended for web
localStorageNoYesVulnerable to XSS
MemoryYesYesLost on refresh

Recommendation: Use HttpOnly cookies for web apps, include CSRF protection.3

Access and Refresh Tokens

Common pattern for better security:

TokenLifespanPurpose
Access Token15-60 minutesAPI authentication
Refresh TokenDays to weeksGet new access tokens

Flow:

  1. User logs in, receives both tokens
  2. Access token used for API calls
  3. When access token expires, use refresh token to get new one
  4. If refresh token expires, user must log in again

JWT Security Best Practices

From OWASP and JWT best practices:3

  1. Short expiration - 15 minutes for access tokens
  2. Strong secrets - Minimum 256 bits for HS256
  3. Use RS256 for distributed systems - Asymmetric keys
  4. Validate all claims - Check iss, aud, exp
  5. Never store sensitive data - Payload is readable
  6. Use HTTPS only - Tokens are bearer credentials

Token Revocation Challenge

JWTs are stateless—you cannot invalidate them server-side without adding state.

Revocation strategies:

  • Short expiration times
  • Refresh token rotation
  • Token blacklist (requires storage)
  • Token versioning in database

Pros and Cons

Advantages:

  • Stateless (no server storage)
  • Works across services/domains
  • Good for APIs and microservices
  • Contains user info (no database lookup)

Disadvantages:

  • Cannot revoke easily
  • Larger than session IDs
  • Payload is readable (not encrypted)
  • Token size increases with claims

OAuth 2.0 and OpenID Connect

OAuth 2.0 is an authorization framework. OpenID Connect (OIDC) adds authentication on top.4

Key Concepts

OAuth 2.0 Roles:

  • Resource Owner: The user
  • Client: Your application
  • Authorization Server: Issues tokens (Google, GitHub, etc.)
  • Resource Server: API with protected resources

OpenID Connect adds:

  • ID Token (JWT with user identity)
  • UserInfo endpoint
  • Standard scopes (openid, profile, email)

Authorization Code Flow

The recommended flow for web applications:5

User          Your App          Auth Server        Resource Server
 |                |                   |                   |
 |-- Click Login ->|                   |                   |
 |                |-- Redirect ------->|                   |
 |                |   (client_id,      |                   |
 |                |    redirect_uri,   |                   |
 |                |    scope, state)   |                   |
 |<---------------|                    |                   |
 |                                     |                   |
 |-- Login at Auth Server ------------>|                   |
 |<-- Redirect to redirect_uri --------|                   |
 |    (code, state)                    |                   |
 |--------------->|                    |                   |
 |                |-- POST /token ---->|                   |
 |                |   (code, secret)   |                   |
 |                |<-- access_token ---|                   |
 |                |    refresh_token   |                   |
 |                |    id_token        |                   |
 |                |                    |                   |
 |                |-- GET /api (token) |------------------>|
 |                |<-- user data ------|-------------------|

PKCE (Proof Key for Code Exchange)

Required for public clients (SPAs, mobile apps):6

  1. Generate random code_verifier
  2. Create code_challenge = SHA256(code_verifier)
  3. Include code_challenge in authorization request
  4. Include code_verifier in token request
  5. Server verifies they match

OAuth Scopes

Scopes limit what access tokens can do:

ProviderCommon Scopes
Googleopenid, email, profile
GitHubread:user, user:email, repo
Microsoftopenid, profile, email, offline_access

Implementation Options

Self-hosted:

  • Auth.js (NextAuth.js) - Next.js and others
  • Passport.js - Node.js middleware
  • Lucia - TypeScript auth library

Managed services:

  • Auth07
  • Clerk
  • Supabase Auth
  • Firebase Auth
  • AWS Cognito

Pros and Cons

Advantages:

  • Users don’t create new passwords
  • Reduced liability (no password storage)
  • Social proof and easy onboarding
  • Access to provider APIs

Disadvantages:

  • Dependency on third parties
  • Complex implementation
  • Privacy concerns for users
  • Provider outages affect your app

Passwordless Authentication

Skip passwords entirely using email links or passkeys.

Send login link to email:

  1. User enters email
  2. Server generates secure token
  3. Email sent with link containing token
  4. User clicks link
  5. Server validates token, creates session

Security requirements:

  • Tokens expire quickly (15-60 minutes)
  • One-time use
  • Cryptographically random (128+ bits)
  • Rate limit requests

WebAuthn and Passkeys

WebAuthn enables passwordless authentication using biometrics or security keys.8

How it works:

  1. Registration: Create public/private key pair
  2. Login: Sign challenge with private key
  3. Server verifies signature with public key

Benefits:

  • Phishing resistant
  • No shared secrets
  • Biometric convenience
  • Cross-device (passkeys)

Browser support: All modern browsers support WebAuthn.

Multi-Factor Authentication (MFA)

Add additional verification factors:9

Factor TypeExamples
KnowledgePassword, PIN
PossessionPhone, security key
InherenceFingerprint, face

TOTP (Time-Based One-Time Password)

Standard for authenticator apps (Google Authenticator, Authy):10

  1. Generate shared secret during setup
  2. User scans QR code with authenticator app
  3. App generates 6-digit codes every 30 seconds
  4. User enters current code to verify

Implementation:

  • Use a library (speakeasy, otplib for Node.js)
  • Store secret encrypted in database
  • Allow backup codes

SMS Codes

Send verification code via SMS.

Concerns:

  • SIM swapping attacks
  • SS7 vulnerabilities
  • NIST discourages SMS for sensitive applications11

Still acceptable for:

  • Low-sensitivity applications
  • Better than no MFA
  • User preference/accessibility

Security Keys (FIDO2)

Hardware tokens using WebAuthn:

  • YubiKey
  • Google Titan Key
  • Built-in platform authenticators

Strongest protection: Phishing-resistant, hardware-backed.

Password Security

If using passwords, follow these guidelines.

Storage Requirements

Never store plaintext passwords. Per OWASP:12

Use adaptive hashing:

  • bcrypt (recommended, cost factor 10+)
  • Argon2id (modern, memory-hard)
  • scrypt (memory-hard alternative)

Do NOT use:

  • MD5, SHA1, SHA256 alone
  • Encryption (reversible)
  • Base64 encoding

Password Requirements

NIST 800-63B guidelines:11

Do:

  • Minimum 8 characters (12+ recommended)
  • Check against breached password lists
  • Allow paste in password fields
  • Show password strength meter

Don’t:

  • Require special characters
  • Force periodic changes
  • Use security questions
  • Limit password length excessively

Example: Password Hashing (Node.js)

const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;

// Hash password
async function hashPassword(password) {
  return await bcrypt.hash(password, SALT_ROUNDS);
}

// Verify password
async function verifyPassword(password, hash) {
  return await bcrypt.compare(password, hash);
}

Security Best Practices

OWASP Authentication Recommendations12

  1. Use HTTPS everywhere - Encrypt all traffic
  2. Implement rate limiting - Prevent brute force
  3. Generic error messages - “Invalid credentials” not “User not found”
  4. Account lockout - After failed attempts, with unlocking mechanism
  5. Secure session management - See session section
  6. Log authentication events - For security monitoring
  7. Implement MFA - Especially for sensitive operations

Common Vulnerabilities

VulnerabilityPrevention
Credential stuffingRate limiting, MFA, breach detection
Brute forceAccount lockout, rate limiting, CAPTCHA
Session hijackingHTTPS, secure cookies, session binding
Session fixationRegenerate session ID on login
XSS token theftHttpOnly cookies, CSP
CSRFSameSite cookies, CSRF tokens

Security Headers

Implement these headers:

Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

Implementation Decision Guide

Choose Session-Based When:

  • Building traditional multi-page apps
  • Team is less experienced with auth
  • Need easy session invalidation
  • Single-domain application

Choose JWT When:

  • Building APIs for multiple clients
  • Microservices architecture
  • Mobile app backend
  • Stateless scaling required

Choose OAuth/Social Login When:

  • Want to reduce friction
  • Users already have Google/GitHub/etc.
  • Don’t want to manage passwords
  • Need access to provider APIs

Choose Passwordless When:

  • Prioritizing user experience
  • Security is paramount (passkeys)
  • Target audience prefers it
  • Email/device is trusted

JavaScript/TypeScript

LibraryUse Case
Auth.js (NextAuth)Next.js, SvelteKit, etc.
LuciaFramework-agnostic, TypeScript
Passport.jsExpress middleware
joseJWT handling

Python

LibraryUse Case
Flask-LoginFlask sessions
Django AuthDjango built-in
AuthlibOAuth/OIDC
PyJWTJWT handling

Managed Services

ServiceStrengths
Auth0Feature-rich, enterprise
ClerkModern DX, React-focused
Supabase AuthPairs with Supabase DB
Firebase AuthGoogle ecosystem
AWS CognitoAWS integration

Summary

MethodSecurityComplexityBest For
SessionsGoodLowWeb apps
JWTGoodMediumAPIs
OAuthGoodMediumSocial login
PasswordlessExcellentMediumModern UX
MFAExcellentMediumHigh security

General recommendations:

  1. Start with sessions for web apps
  2. Add OAuth for social login
  3. Implement MFA for sensitive accounts
  4. Consider passwordless for modern UX
  5. Always follow OWASP guidelines

Further Reading


References

Footnotes

  1. OWASP. “Session Management Cheat Sheet.” https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html

  2. IETF. “RFC 7519 - JSON Web Token (JWT).” https://datatracker.ietf.org/doc/html/rfc7519 2

  3. OWASP. “JSON Web Token Cheat Sheet.” https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html 2

  4. IETF. “RFC 6749 - The OAuth 2.0 Authorization Framework.” https://datatracker.ietf.org/doc/html/rfc6749

  5. OpenID Foundation. “OpenID Connect Core 1.0.” https://openid.net/specs/openid-connect-core-1_0.html

  6. IETF. “RFC 7636 - Proof Key for Code Exchange (PKCE).” https://datatracker.ietf.org/doc/html/rfc7636

  7. Auth0. “Documentation.” https://auth0.com/docs

  8. W3C. “Web Authentication (WebAuthn).” https://www.w3.org/TR/webauthn-2/

  9. NIST. “Digital Identity Guidelines - Authentication.” https://pages.nist.gov/800-63-3/sp800-63b.html

  10. IETF. “RFC 6238 - TOTP: Time-Based One-Time Password Algorithm.” https://datatracker.ietf.org/doc/html/rfc6238

  11. NIST. “SP 800-63B - Digital Identity Guidelines.” https://pages.nist.gov/800-63-3/sp800-63b.html 2

  12. OWASP. “Authentication Cheat Sheet.” https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html 2