~/projects/app $ Help me refactor this authentication function to use async/await and add better error handling

I'll help you refactor the authentication function. Let me analyze the current code and improve it with async/await syntax and proper error handling.

Here are the changes I'll make:

  • Convert callback-based code to async/await
  • Add try/catch blocks for error handling
  • Include specific error types for different failure modes
  • Add input validation
src/auth/authenticate.js
async function authenticate(credentials) {
  const { username, password } = credentials;

  // Input validation
  if (!username || !password) {
    throw new ValidationError('Username and password required');
  }

  try {
    const user = await findUser(username);

    if (!user) {
      throw new AuthError('User not found');
    }

    const isValid = await verifyPassword(password, user.hash);

    if (!isValid) {
      throw new AuthError('Invalid password');
    }

    return generateToken(user);
  } catch (error) {
    if (error instanceof AuthError) {
      throw error;
    }
    throw new AuthError('Authentication failed', { cause: error });
  }
}

Here's the diff showing what changed:

src/auth/authenticate.js +18 -12
- function authenticate(credentials, callback) {
+ async function authenticate(credentials) {
      const { username, password } = credentials;
-   if (!username || !password) {
-     return callback(new Error('Missing credentials'));
-   }
+   // Input validation
+   if (!username || !password) {
+     throw new ValidationError('Username and password required');
+   }
    
-   findUser(username, (err, user) => {
-     if (err) return callback(err);
-     if (!user) return callback(new Error('Not found'));
+   try {
+     const user = await findUser(username);
+     if (!user) {
+       throw new AuthError('User not found');
+     }

The refactored code is cleaner and provides better error messages. Want me to also add rate limiting or session management?

~/projects/app $ Yes, add rate limiting please

I'll add rate limiting using a token bucket algorithm. This will prevent brute force attacks by limiting login attempts.

src/auth/rateLimit.js
const rateLimiter = new Map();

export function checkRateLimit(ip, maxAttempts = 5) {
  const now = Date.now();
  const windowMs = 15 * 60 * 1000; // 15 minutes

  const record = rateLimiter.get(ip) || { count: 0, start: now };

  if (now - record.start > windowMs) {
    record.count = 1;
    record.start = now;
  } else {
    record.count++;
  }

  rateLimiter.set(ip, record);

  return record.count <= maxAttempts;
}

Created src/auth/rateLimit.js

Updated src/auth/authenticate.js