Node.js Authentication: Complete Theory & Practice Guide

Understand sessions, JWT, OAuth, and production-grade authentication security patterns.

SessionsJWTOAuth

Table of Contents

  1. Theory: Authentication Fundamentals
  2. Theory: Session-Based Authentication
  3. Theory: JWT Authentication
  4. Theory: OAuth 2.0 & Social Login
  5. Theory: Password Security
  6. Basic: Local Authentication
  7. Basic: JWT Implementation
  8. Advanced: OAuth with Passport
  9. Best Practices & Security
  10. Interview Q&A + MCQ
  11. Contextual Learning Links

1. Theory: Authentication Fundamentals

┌─────────────────────────────────────────────────────────────┐
│                   Security Concepts                           │
├─────────────────────────────────────────────────────────────┤
│ Authentication: "WHO are you?"                               │
│ • Proving identity (login/password/biometric)                │
│ Authorization: "WHAT can you do?"                            │
│ • Permissions and access levels                              │
│ Example:                                                     │
│ • Authentication: Login with email/password                  │
│ • Authorization: Admin can delete users                      │
└─────────────────────────────────────────────────────────────┘
FactorExamplesSecurity Level
Something you KNOWPassword, PINLow
Something you HAVEPhone, tokenMedium
Something you AREFingerprint, face IDHigh
Something you DOVoice/signature patternMedium
Somewhere you AREGPS, IP geofenceLow
const mfaTheory = {
  description: 'Two or more different authentication factors',
  commonImplementations: [
    'Password + SMS code',
    'Password + TOTP app',
    'Password + biometric'
  ],
  protectsAgainst: ['Password theft', 'Credential stuffing', 'Phishing attacks']
};
const authFlows = {
  SPA: {
    flow: ['Login', 'Server returns JWT', 'Client stores token', 'Send Authorization header'],
    pros: 'Stateless and scalable',
    cons: 'Token storage concerns'
  },
  SSR: {
    flow: ['Login', 'Server session created', 'HTTP-only cookie set'],
    pros: 'Strong cookie security model',
    cons: 'Stateful session storage required'
  },
  mobile: {
    flow: ['Login', 'Access + refresh tokens', 'Secure storage', 'Refresh cycle'],
    pros: 'Good UX',
    cons: 'Token lifecycle complexity'
  }
};

2. Theory: Session-Based Authentication

┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  User   │     │ Client  │     │ Server  │     │  Store  │
└────┬────┘     └────┬────┘     └────┬────┘     └────┬────┘
     │ Login request │               │               │
     │──────────────►│──────────────►│ Create session│
     │               │               │──────────────►│
     │               │ Set cookie sid│               │
     │               │◄──────────────│               │
     │ Next request  │               │ Lookup session│
     │──────────────►│──────────────►│──────────────►│
└───────────────────────────────────────────────────────────────┘
const sessionStorageOptions = {
  'In-Memory': { pros: ['Fast', 'Simple'], cons: ['Lost on restart', 'Not scalable'], useCase: 'Development' },
  'Redis': { pros: ['Persistent', 'Fast', 'Scalable'], cons: ['Extra infra'], useCase: 'Production' },
  'Database': { pros: ['Persistent'], cons: ['Slower than Redis'], useCase: 'Small apps' },
  'Memcached': { pros: ['Very fast'], cons: ['No persistence'], useCase: 'Caching-heavy workloads' }
};
AttributeDescriptionSecurity Impact
HttpOnlyBlocks JavaScript accessCritical (XSS mitigation)
SecureSent only over HTTPSCritical (MITM mitigation)
SameSiteCross-site send rulesCSRF mitigation
MaxAge/ExpiresCookie lifetimeLimits token window
Domain/PathScope controlReduces exposure surface

3. Theory: JWT Authentication

┌─────────────────────────────────────────────────────────────┐
│                         JWT Token                            │
├─────────────────────────────────────────────────────────────┤
│ xxxxx.yyyyy.zzzzz                                            │
│ Header . Payload . Signature                                 │
│ Header: {"alg":"HS256","typ":"JWT"}                          │
│ Payload: {"sub":"123","name":"John","iat":...,"exp":...}     │
└─────────────────────────────────────────────────────────────┘
ClaimNameDescriptionRequired?
issIssuerToken issuerOptional
subSubjectUser identifierRecommended
audAudienceIntended recipientOptional
expExpirationExpiry timestampRecommended
iatIssued AtCreation timestampRecommended
jtiJWT IDToken unique identifierOptional
AspectJWTSession
StorageClient-sideServer-side store
StatelessnessYesNo
ScalabilityExcellentNeeds shared session store
InvalidationHard until expiryEasy (delete session)
Best fitAPIs/SPAs/mobileTraditional SSR apps
const refreshTokenFlow = {
  flow: [
    'Login returns access + refresh tokens',
    'Access token used for requests',
    'On expiry, send refresh token',
    'Server validates and rotates tokens'
  ],
  benefits: [
    'Limits impact of access token theft',
    'Supports refresh token revocation',
    'Avoids storing credentials on device'
  ]
};

4. Theory: OAuth 2.0 & Social Login

┌─────────────────────────────────────────────────────────────┐
│                      OAuth 2.0 Roles                         │
├─────────────────────────────────────────────────────────────┤
│ Resource Owner (User) authorizes Client (Your App)          │
│ Client exchanges auth code for token from Authorization srv │
│ Client uses token to access Resource server user data       │
└─────────────────────────────────────────────────────────────┘
Grant TypeUse CaseSecurity Level
Authorization CodeServer-side web appsHigh
Authorization Code + PKCEMobile/SPAHigh
Client CredentialsMachine-to-machineHigh
Password GrantLegacy trusted appsLow
ImplicitDeprecatedLow
const oauthProviders = {
  Google: {
    authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
    tokenUrl: 'https://oauth2.googleapis.com/token',
    userInfoUrl: 'https://www.googleapis.com/oauth2/v2/userinfo',
    scopes: ['email', 'profile']
  },
  GitHub: {
    authUrl: 'https://github.com/login/oauth/authorize',
    tokenUrl: 'https://github.com/login/oauth/access_token',
    userInfoUrl: 'https://api.github.com/user',
    scopes: ['user:email']
  }
};

5. Theory: Password Security

AlgorithmSpeedSecurityRecommendation
bcryptSlow (configurable)HighRecommended
scryptVery slowVery highGood
argon2SlowHighestExcellent
PBKDF2ConfigurableModerateAcceptable legacy
MD5/SHA1FastBrokenNever use
const bcryptComplexity = {
  definition: 'Rounds = 2^workFactor',
  recommendation: { current: '10-12', highSecurity: '12-14' }
};
const passwordResetFlow = {
  flow: [
    'Generate cryptographically random reset token',
    'Store token hash + expiry',
    'Email reset link',
    'Verify token and expiry',
    'Set new password',
    'Invalidate token and sessions'
  ],
  securityMeasures: [
    'Rate limit reset requests',
    'Avoid revealing whether email exists',
    'Expire/reset token after short window'
  ]
};
const lockoutStrategies = {
  progressiveDelay: '1s → 5s → 30s → 5min',
  accountLockout: 'Lock after repeated failures',
  captchaAfterFailures: 'Add captcha after threshold'
};

6. Basic: Local Authentication

npm install express-session connect-redis redis
// session-config.js
const sessionConfig = {
  store: new RedisStore({ client: redisClient }),
  name: 'sessionId',
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: 1000 * 60 * 60 * 24
  }
};
// local auth highlights
router.post('/register', validateRegister, async (req, res) => {
  const hashedPassword = await bcrypt.hash(req.body.password, 12);
  // save user + create session
});

router.post('/login', loginLimiter, async (req, res) => {
  // validate user + bcrypt.compare + create session
});

router.post('/logout', (req, res) => {
  req.session.destroy(() => { res.clearCookie('sessionId'); res.json({ message: 'Logout successful' }); });
});

7. Basic: JWT Implementation

npm install jsonwebtoken bcrypt
// jwt-auth.js
const ACCESS_TOKEN_EXPIRY = '15m';
const REFRESH_TOKEN_EXPIRY = '7d';

function generateTokens(userId, role) {
  const payload = { sub: userId, role };
  const accessToken = jwt.sign(payload, JWT_SECRET, { expiresIn: ACCESS_TOKEN_EXPIRY });
  const refreshToken = jwt.sign(payload, JWT_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRY });
  return { accessToken, refreshToken };
}

function authenticateJWT(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) return res.status(401).json({ error: 'No token provided' });
  try {
    const decoded = jwt.verify(authHeader.split(' ')[1], JWT_SECRET);
    req.user = { id: decoded.sub, role: decoded.role };
    next();
  } catch {
    return res.status(403).json({ error: 'Invalid token' });
  }
}
// refresh flow
router.post('/jwt/refresh', (req, res) => {
  const { refreshToken } = req.body;
  // validate stored refresh token, rotate, return new pair
});

8. Advanced: OAuth with Passport

npm install passport passport-google-oauth20 passport-github2 express-session
// passport-config.js
passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser(async (id, done) => done(null, await User.findById(id)));

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback'
}, async (accessToken, refreshToken, profile, done) => {
  // find or create user
  done(null, user);
}));

router.get('/auth/google', passport.authenticate('google'));
router.get('/auth/google/callback',
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => res.redirect(`/auth-success?token=${generateJWT(req.user)}`)
);
// GitHub strategy similar pattern
passport.use(new GitHubStrategy({
  clientID: process.env.GITHUB_CLIENT_ID,
  clientSecret: process.env.GITHUB_CLIENT_SECRET,
  callbackURL: '/auth/github/callback'
}, async (accessToken, refreshToken, profile, done) => done(null, user)));

9. Best Practices & Security

// security headers
app.use(helmet({
  hsts: { maxAge: 31536000, includeSubDomains: true, preload: true }
}));
app.use((req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
  next();
});
// csrf
const csrfProtection = csrf({
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict'
  }
});
app.use('/api', csrfProtection);
// secure password reset
const resetToken = crypto.randomBytes(32).toString('hex');
const resetTokenHash = crypto.createHash('sha256').update(resetToken).digest('hex');
// store hash + expiry, email raw token
// on use: hash incoming token and compare against stored hash
const securityChecklist = {
  passwords: ['Hash with bcrypt', 'Strong policy', 'No password logging'],
  sessions: ['HTTP-only/Secure/SameSite', 'session timeout', 'invalidate on logout'],
  jwt: ['Short-lived access token', 'refresh rotation', 'algorithm validation'],
  general: ['Rate limiting', 'HTTPS', 'security logs', 'CSRF tokens', 'Helmet']
};
AttackDescriptionMitigation
Brute ForceRepeated password guessesRate limit, CAPTCHA, lockout
Credential StuffingReused leaked credentialsMFA, breach checks
Session FixationForced known session IDRegenerate session on login
XSSInjected script executionHTTP-only cookies, CSP, sanitization
CSRFForged authenticated requestCSRF tokens + SameSite
MITMTraffic interceptionHTTPS, HSTS, secure cookies
Token ReplayReuse stolen tokenShort expiry, revocation, rotation

10 Interview Questions + 10 MCQs

1Authentication vs authorization?easy
Answer: Authentication verifies identity; authorization controls allowed actions.
2Why use MFA?easy
Answer: It reduces account compromise risk even when password is stolen.
3When prefer sessions over JWT?medium
Answer: SSR apps needing strict cookie-based security and easy server-side invalidation.
4When prefer JWT?medium
Answer: APIs/SPAs/mobile where stateless auth and distributed verification are useful.
5Why avoid plain JWT long lifetime?medium
Answer: Stolen tokens remain valid too long; use short access tokens + refresh flow.
6What makes password hashing secure?easy
Answer: Slow, salted, adaptive hashing (bcrypt/argon2/scrypt).
7Why `HttpOnly` on auth cookies?easy
Answer: Prevents JavaScript access, reducing token theft via XSS.
8OAuth authorization code flow advantage?hard
Answer: Better security by exchanging code server-side and protecting client secrets.
9How to defend login endpoint abuse?easy
Answer: Rate limiting, lockout policies, CAPTCHA, and suspicious-event monitoring.
10Why rotate refresh tokens?hard
Answer: Limits replay and provides stronger revocation semantics.

10 Authentication MCQs

1

Authentication answers:

AWho are you?
BWhat can you do?
CWhere is server?
DHow much RAM?
Explanation: Authentication verifies identity.
2

Most recommended password hashing:

Abcrypt/argon2
BMD5
CSHA1 plain
DBase64
Explanation: Use adaptive slow hash algorithms with salts.
3

Cookie flag preventing JS access:

AHttpOnly
BPath
CExpires
DDomain
Explanation: HttpOnly blocks `document.cookie` access.
4

JWT stands for:

AJava Web Token
BJSON Web Token
CJSON Wire Transfer
DJavaScript Wrapped Token
Explanation: JWT = JSON Web Token.
5

Best token strategy for APIs:

AShort access token + refresh token rotation
BNever-expiring token
CNo signature validation
DPlain text token in URL always
Explanation: Limits replay risk while preserving UX.
6

OAuth authorization code flow primarily uses:

AServer-side code exchange for token
BPassword sharing with client app
CNo redirects
DNo user consent
Explanation: Authorization code is exchanged for token securely.
7

Main CSRF defense with forms:

ACSRF token + SameSite cookies
BLonger password
CBase64 cookie values
DDisable HTTPS
Explanation: CSRF token validation stops forged cross-site requests.
8

Session-based auth is easier to invalidate because:

AServer can delete session data directly
BTokens are immutable
CNo cookies needed
DNo state exists
Explanation: Stateful storage allows immediate invalidation.
9

Best response for invalid login:

AGeneric "Invalid credentials"
B"Email not found" explicitly
CReturn hash for debugging
DReturn stack trace
Explanation: Avoid user enumeration disclosures.
10

Critical production requirement:

AHTTPS + secure cookies + rate limiting
BDisable logging entirely
CStore secrets in code
DSkip token validation
Explanation: These are foundational controls for auth security.