hectoday
DocsCoursesChangelog GitHub
DocsCoursesChangelog GitHub

Access Required

Enter your access code to view courses.

Invalid code

← All courses Securing Your API with @hectoday/http

The Threat Landscape

  • What Could Go Wrong
  • Project Setup

Brute-Force Protection

  • Rate Limiting Login Attempts
  • Account Lockout
  • Timing Attack Prevention

CSRF Protection

  • What Is CSRF?
  • CSRF Tokens
  • CSRF for API Consumers

Token Hardening

  • Refresh Token Rotation
  • Token Revocation
  • Secure Token Storage

Password Reset

  • The Password Reset Flow
  • Building the Reset Routes
  • Reset Security

Putting It All Together

  • Security Headers
  • Logging and Monitoring
  • Security Checklist
  • Capstone: Hardened Auth API

Logging and Monitoring

Why logging matters for security

You cannot defend against what you cannot see. Without logs, a brute-force attack looks like normal traffic. A successful account takeover is invisible. A password reset flood goes unnoticed.

Security logging records the events that tell you something is wrong. Rate limit hits, failed logins, account lockouts, password resets, suspicious patterns — these are the signals.

What to log

Throughout this course, we have added log() calls at key points. Here is the complete list of security events worth logging:

Authentication events

log("login_success", { email, ip, userId });
log("login_failed", { email, ip, reason: "wrong_password" });
log("login_failed", { email, ip, reason: "user_not_found" });
log("logout", { userId, ip });

Rate limiting and lockout

log("rate_limited", { key: "ip", ip, email });
log("rate_limited", { key: "email", ip, email });
log("login_locked", { email, ip });

Password events

log("reset_token_created", { email });
log("reset_requested_unknown_email", { email, ip });
log("reset_failed", { ip, reason: "invalid_or_expired_token" });
log("password_reset", { userId, ip });
log("password_changed", { userId, ip });

Token events

log("refresh_token_reuse", { family, userId });
log("token_revoked", { jti, userId });

Request logging

log("request", { method, path, status, duration, ip });
log("unhandled_error", { error, ip });

What NEVER to log

[!WARNING] Never log these values. If your logs are compromised, these become attack material.

Passwords. Not the plain text, not the hash. Logging the request body of a login endpoint would capture the password.

// WRONG
log("login_attempt", { email, password }); // password in logs!
log("login_attempt", { body: c.input.body }); // body contains password!

// CORRECT
log("login_attempt", { email });

Session IDs. If session IDs appear in logs and the logs are compromised, the attacker can hijack sessions.

// WRONG
log("session_created", { sessionId, userId });

// CORRECT
log("session_created", { userId });

Access tokens and refresh tokens. Same reason as session IDs.

Reset tokens. Same reason — a leaked reset token in logs could be used to reset a password.

Full request bodies for sensitive endpoints. Login, signup, password change, and reset endpoints all receive sensitive data in the body. Log the event, not the data.

Patterns to watch for

With structured logging in place, you can build alerts for:

Brute-force: Many login_failed events for the same email in a short period.

Credential stuffing: Many login_failed events from the same IP with different emails.

Account takeover: A login_success from an unusual IP or country, followed by a password_changed.

Password reset flood: Many reset_token_created events for the same email.

Token theft: A refresh_token_reuse event (someone used a token that was already consumed).

In a production system, you would feed these logs into a monitoring tool (Datadog, Grafana, CloudWatch) and set up alerts. For now, console.log with JSON output gives you the foundation.

Exercises

Exercise 1: Review all the log() calls in your codebase. Make sure none of them include passwords, tokens, or session IDs. Search for password, token, session in your log calls.

Exercise 2: Simulate a brute-force attack (send many failed login requests) and look at the log output. Can you identify the attack from the logs alone?

Exercise 3: Add a log("signup", { email, ip }) call to the signup route. What else would you log on signup? (Consider: duplicate email attempts, validation failures.)

Why should you never log passwords, even hashed ones?

← Security Headers Security Checklist →

© 2026 hectoday. All rights reserved.