Skip to content

A comprehensive authentication and OTP error handling system built on the @khni/error-handler foundation, designed for seamless integration with the @khni/auth package. This TypeScript/JavaScript library provides structured error classes, type-safe error codes, and consistent HTTP response mappings for robust authentication workflows.

License

Notifications You must be signed in to change notification settings

khni/auth-errors

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@khni/auth-errors

A comprehensive authentication and OTP error handling system built on the @khni/error-handler foundation, designed for seamless integration with the @khni/auth package. This TypeScript/JavaScript library provides structured error classes, type-safe error codes, and consistent HTTP response mappings for robust authentication workflows.

Installation

npm install @khni/auth-errors
pnpm add  @khni/auth-errors
yarn add  @khni/auth-errors

Features

  • 🏷️ Type-safe error codes with full TypeScript support
  • 🎯 Separated concerns - Authentication and OTP errors in separate modules
  • πŸ“Š Domain vs Unexpected errors - Clear distinction between user-facing and system errors
  • πŸ”§ Factory patterns - Consistent error creation with utilities
  • πŸ“ Comprehensive documentation - Full JSDoc support for API Extractor
  • 🚦 HTTP status mapping - Automatic status code and message mapping
  • πŸ›‘οΈ Type guards - Runtime error type checking

Quick Start

import {
  AuthDomainError,
  AuthUnexpectedError,
  OtpDomainError,
  AuthErrorCodes,
  OtpErrorCodes,
} from "@khni/auth-errors";

// Throw authentication domain errors
if (emailAlreadyExists) {
  throw new AuthDomainError(AuthErrorCodes.AUTH_USED_EMAIL);
}

// Throw OTP domain errors
if (otpIsInvalid) {
  throw new OtpDomainError(OtpErrorCodes.OTP_INVALID);
}

// Throw unexpected errors with original cause
try {
  await createUser(userData);
} catch (error) {
  throw new AuthUnexpectedError(
    AuthErrorCodes.AUTH_USER_CREATION_FAILED,
    error
  );
}

Error Categories

Authentication Errors

Domain Errors (User-facing, expected):

  • AUTH_USED_EMAIL - Email already registered
  • INCORRECT_CREDENTIALS - Invalid email/password
  • INVALID_ACCESS_TOKEN - Malformed or invalid JWT
  • REFRESH_TOKEN_INVALID - Expired or revoked refresh token
  • And 15+ more...

Unexpected Errors (System-level):

  • AUTH_USER_CREATION_FAILED - Database failure during user creation
  • FINDING_USER_FAILED - User search operation failed
  • ISSUE_TOKEN_FAILED - JWT generation failure
  • And 7+ more...

OTP Errors

Domain Errors (User-facing, expected):

  • OTP_INVALID - Incorrect OTP code
  • OTP_EXPIRED - OTP code has expired
  • OTP_TOKEN_INVALID - Invalid OTP session token

Unexpected Errors (System-level):

  • OTP_CREATION_FAILED - OTP generation service failure
  • OTP_VERIFICATION_FAILED - OTP validation service failure

Usage Examples

Basic Error Throwing

import {
  AuthDomainError,
  AuthUnexpectedError,
  OtpDomainError,
  AuthErrorCodes,
  OtpErrorCodes,
} from "@khni/auth-errors";

// Authentication domain errors
function registerUser(email: string) {
  if (await userExists(email)) {
    throw new AuthDomainError(
      AuthErrorCodes.AUTH_USED_EMAIL,
      `Email ${email} is already registered`,
      { email, source: "registration" }
    );
  }
}

// OTP domain errors
function verifyOtp(userId: string, otpCode: string) {
  const storedOtp = await getStoredOtp(userId);
  if (storedOtp.code !== otpCode) {
    throw new OtpDomainError(
      OtpErrorCodes.OTP_INVALID,
      "Invalid verification code",
      { userId, attempts: storedOtp.attempts }
    );
  }
}

// Unexpected errors with cause
async function resetPassword(userId: string, newPassword: string) {
  try {
    await updatePassword(userId, newPassword);
  } catch (error) {
    throw new AuthUnexpectedError(
      AuthErrorCodes.PASSWORD_RESET_FAILED,
      error,
      "Password reset operation failed",
      { userId, timestamp: new Date() }
    );
  }
}

Using Factory Methods

import { AuthErrorFactories, OtpErrorFactories } from "@khni/auth-errors";

// Simplified error creation
function authenticateUser(email: string, password: string) {
  const user = await findUserByEmail(email);

  if (!user) {
    throw AuthErrorFactories.domain("USER_IS_NOT_EXIST", { email });
  }

  if (!user.verified) {
    throw AuthErrorFactories.domain("AUTH_UNVERIFIED_EMAIL", {
      userId: user.id,
    });
  }

  if (otpAttempts > 3) {
    throw OtpErrorFactories.domain("OTP_INVALID", {
      userId: user.id,
      attempts: otpAttempts,
    });
  }
}

Error Handling in Express

import {
  AuthError,
  OtpError,
  isAuthDomainError,
  isOtpDomainError,
  getAuthErrorResponse,
  getOtpErrorResponse,
} from "@khni/auth-errors";

app.use((error: Error, req: Request, res: Response, next: NextFunction) => {
  // Handle authentication errors
  if (error instanceof AuthError) {
    const config = getAuthErrorResponse(error.code);

    if (isAuthDomainError(error)) {
      // Log domain errors as warnings
      logger.warn("Auth domain error", { code: error.code, meta: error.meta });
    } else {
      // Log unexpected errors with full details
      logger.error("Auth unexpected error", {
        code: error.code,
        cause: error.cause,
        meta: error.meta,
      });
    }

    return res.status(config.statusCode).json({
      error: config.responseMessage,
      code: error.code,
    });
  }

  // Handle OTP errors
  if (error instanceof OtpError) {
    const config = getOtpErrorResponse(error.code);

    if (isOtpDomainError(error)) {
      logger.warn("OTP domain error", { code: error.code, meta: error.meta });
    } else {
      logger.error("OTP unexpected error", {
        code: error.code,
        cause: error.cause,
        meta: error.meta,
      });
    }

    return res.status(config.statusCode).json({
      error: config.responseMessage,
      code: error.code,
    });
  }

  // Handle other errors
  next(error);
});

API Reference

Core Classes

AuthError

Base class for all authentication errors.

AuthDomainError

Expected business logic errors during authentication.

AuthUnexpectedError

System-level failures during authentication.

OtpError

Base class for all OTP errors.

OtpDomainError

Expected business logic errors during OTP operations.

OtpUnexpectedError

System-level failures during OTP operations.

Utility Functions

getAuthErrorResponse(code: AuthErrorCodesType)

Returns HTTP status code and message for authentication errors.

getOtpErrorResponse(code: OtpErrorCodesType)

Returns HTTP status code and message for OTP errors.

Type Guards

  • isAuthDomainError(error: unknown)
  • isAuthUnexpectedError(error: unknown)
  • isOtpDomainError(error: unknown)
  • isOtpUnexpectedError(error: unknown)

Factory Classes

AuthErrorFactories

  • .domain(code, meta?) - Create domain errors
  • .unexpected(code, cause, meta?) - Create unexpected errors

OtpErrorFactories

  • .domain(code, meta?) - Create domain errors
  • .unexpected(code, cause, meta?) - Create unexpected errors

Error Codes Reference

Authentication Error Codes

Domain Errors

Code HTTP Status Message Description
AUTH_USED_EMAIL 409 Email already registered Email exists during registration
AUTH_USED_IDENTIFIER 409 Identifier already registered Username/identifier taken
AUTH_UNVERIFIED_EMAIL 403 Email verification required User needs to verify email
INCORRECT_CREDENTIALS 401 Invalid credentials Wrong email/password
USER_NOT_LOCAL 400 External authentication required OAuth user tried local auth
REFRESH_TOKEN_INVALID 401 Refresh token is invalid or expired Refresh token validation failed
INVALID_ACCESS_TOKEN 401 Access token is invalid or expired Malformed JWT token
EXPIRED_ACCESS_TOKEN 401 Access token is expired JWT token expired
MISSING_ACCESS_TOKEN 401 Access token is missing No Authorization header
MISSING_REFRESH_TOKEN 400 You are already logged out No refresh token during logout
USER_IS_NOT_EXIST 400 Email does not exist User not found

Unexpected Errors

Code HTTP Status Message Description
FINDING_USER_FAILED 500 Something went wrong while finding the user Database search failure
AUTH_USER_CREATION_FAILED 500 Account creation failed User creation database failure
ISSUE_TOKEN_FAILED 400 Unexpected error while issuing tokens JWT generation failure
PASSWORD_RESET_FAILED 500 Password Reset Failed Password update operation failed
REFRESHTOKEN_REVOKE_FAILED 500 Failed to Logout Refresh token revocation failed
REFRESHTOKEN_CREATE_FAILED 500 Failed to create refresh token Refresh token creation failed
REFRESHTOKEN_VERIFY_FAILED 500 Failed to verify refresh token Refresh token verification failed
LOGIN_FAILED 500 Something went wrong while login General login process failure

OTP Error Codes

Domain Errors

Code HTTP Status Message Description
OTP_INVALID 401 The OTP you entered is incorrect Wrong OTP code provided
OTP_EXPIRED 401 The OTP is expired OTP code has expired
TOKEN_EXPIRED 401 Token is expired OTP session token expired
OTP_TOKEN_INVALID 401 Please request new OTP Invalid or expired OTP token

Unexpected Errors

Code HTTP Status Message Description
OTP_CREATION_FAILED 500 Something went wrong while creating OTP OTP generation service failure
OTP_VERIFICATION_FAILED 500 Something went wrong while verifying OTP OTP validation service failure

Best Practices

1. Error Handling Strategy

// Use domain errors for business logic
if (!user.exists) {
  throw new AuthDomainError("USER_IS_NOT_EXIST");
}

// Use unexpected errors for system failures
try {
  await databaseOperation();
} catch (error) {
  throw new AuthUnexpectedError("FINDING_USER_FAILED", error);
}

2. Metadata for Debugging

// Include relevant context in meta
throw new AuthDomainError("INCORRECT_CREDENTIALS", "Multiple failed attempts", {
  userId: user.id,
  attempts: loginAttempts,
  ip: request.ip,
});

3. Error Recovery

import { isOtpDomainError } from "@khni/auth-errors";

try {
  await verifyOtp(userId, otpCode);
} catch (error) {
  if (isOtpDomainError(error)) {
    // User can retry with new OTP
    return res.status(401).json({
      error: error.message,
      canRetry: true,
    });
  }
  throw error; // Re-throw unexpected errors
}

Integration with Logging

import {
  AuthError,
  isAuthDomainError,
  isAuthUnexpectedError,
} from "@khni/auth-errors";

function logAuthError(error: AuthError) {
  if (isAuthDomainError(error)) {
    logger.warn("Authentication domain error", {
      code: error.code,
      message: error.message,
      meta: error.meta,
    });
  } else if (isAuthUnexpectedError(error)) {
    logger.error("Authentication system error", {
      code: error.code,
      message: error.message,
      cause: error.cause,
      meta: error.meta,
      stack: error.stack,
    });

    // Send to error monitoring service
    sentry.captureException(error);
  }
}

Migration Guide

From v1 to v2

If you're migrating from a previous version:

  1. Import paths changed:

    // Before
    import { AuthError } from "@khni/auth-errors";
    
    // After
    import { AuthError } from "@khni/auth-errors";
    // Paths remain the same but internal structure changed
  2. Error code constants are now enums:

    // Before
    throw new Error("USER_NOT_FOUND");
    
    // After
    throw new AuthDomainError(AuthErrorCodes.USER_IS_NOT_EXIST);

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/new-error-codes
  3. Commit your changes: git commit -am 'Add new error codes'
  4. Push to the branch: git push origin feature/new-error-codes
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Support

About

A comprehensive authentication and OTP error handling system built on the @khni/error-handler foundation, designed for seamless integration with the @khni/auth package. This TypeScript/JavaScript library provides structured error classes, type-safe error codes, and consistent HTTP response mappings for robust authentication workflows.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published