UNPKG

mbkauthe

Version:

MBKTech's reusable authentication system for Node.js applications.

574 lines (454 loc) 15.7 kB
# Error Messages & Codes MBKAuthe provides a comprehensive error messaging system with standardized error codes and user-friendly messages. ## Overview The error messaging system provides: - **Standardized Error Codes**: Consistent error codes across all operations - **User-Friendly Messages**: Clear, actionable error messages for end users - **Developer Context**: Detailed error information for logging and debugging - **Helpful Hints**: Guidance on how to resolve errors - **Structured Responses**: Consistent error response format - **Dynamic Documentation**: Error code page at `/mbkauthe/ErrorCode` auto-generates from `lib/utils/errors.js` ## Dynamic Error Documentation The error code documentation page (`/mbkauthe/ErrorCode`) is **automatically generated** from the `lib/utils/errors.js` file. This ensures the documentation is always in sync with the actual error codes in the system. ### Adding New Errors To add a new error code: 1. **Define the error code** in `ErrorCodes` enum: ```javascript export const ErrorCodes = { // ... existing codes YOUR_NEW_ERROR: 1400, }; ``` 2. **Add error details** to `ErrorMessages` object: ```javascript export const ErrorMessages = { // ... existing messages [ErrorCodes.YOUR_NEW_ERROR]: { message: "Internal message for logging", userMessage: "User-friendly error message", hint: "Helpful tip to resolve the issue" }, }; ``` 3. **Include in category array** in `misc.js` route handler: ```javascript const categories = [ // ... existing categories { name: "Your Category Name", range: "1400-1499", codes: [1400, 1401, 1402] // Add your new codes here } ]; ``` The error code page will automatically display your new error without any additional changes. ## Error Code Ranges | Range | Category | Example | |-------|----------|---------| | 600-699 | Authentication | Invalid credentials, account inactive | | 700-799 | Two-Factor Authentication | Invalid 2FA token, 2FA not configured | | 800-899 | Session Management | Session expired, invalid session | | 900-999 | Authorization | Insufficient permissions, role not allowed | | 1000-1099 | Input Validation | Missing fields, invalid format | | 1100-1199 | Rate Limiting | Too many requests | | 1200-1299 | Server Errors | Internal error, database error | | 1300-1399 | OAuth | GitHub not linked, OAuth failed | ## Error Codes Reference ### Authentication Errors (600-699) #### `601 - INVALID_CREDENTIALS` General authentication failure. ```javascript { errorCode: 601, message: "The username or password you entered is incorrect. Please try again.", hint: "Check your spelling and make sure Caps Lock is off" } ``` #### `602 - USER_NOT_FOUND` User account doesn't exist. ```javascript { errorCode: 602, message: "We couldn't find an account with that username.", hint: "Please check the username and try again" } ``` #### `603 - INCORRECT_PASSWORD` Password doesn't match. ```javascript { errorCode: 603, message: "The password you entered is incorrect.", hint: "Make sure you're using the correct password for this account" } ``` #### `604 - ACCOUNT_INACTIVE` User account is deactivated. ```javascript { errorCode: 604, message: "Your account has been deactivated.", hint: "Please contact your administrator to reactivate your account" } ``` #### `605 - APP_NOT_AUTHORIZED` User not authorized for this application. ```javascript { errorCode: 605, message: "You don't have permission to access this application.", hint: "Contact your administrator if you believe this is an error" } ``` ### 2FA Errors (700-799) #### `701 - TWO_FA_REQUIRED` 2FA verification needed. #### `702 - TWO_FA_INVALID_TOKEN` Invalid 2FA code. #### `703 - TWO_FA_NOT_CONFIGURED` 2FA not set up. #### `704 - TWO_FA_EXPIRED` 2FA code has expired. ### Session Errors (800-899) #### `801 - SESSION_EXPIRED` Session has expired. #### `802 - SESSION_INVALID` Session is no longer valid. #### `803 - SESSION_NOT_FOUND` No active session found. ### Authorization Errors (900-999) #### `901 - INSUFFICIENT_PERMISSIONS` User lacks required permissions. #### `902 - ROLE_NOT_ALLOWED` User's role doesn't have access. ### Input Validation Errors (1000-1099) #### `1001 - MISSING_REQUIRED_FIELD` Required field not provided. #### `1002 - INVALID_USERNAME_FORMAT` Username format is invalid. #### `1003 - INVALID_PASSWORD_LENGTH` Password doesn't meet length requirements. #### `1004 - INVALID_TOKEN_FORMAT` Token format is incorrect. #### `1005 - INVALID_AUTH_TOKEN` The provided API token is invalid. #### `1006 - API_TOKEN_EXPIRED` The provided API token has expired. #### `1007 - TOKEN_SCOPE_INSUFFICIENT` Token scope doesn't allow the requested operation. ```javascript { errorCode: 1007, message: "This API token doesn't have permission for this operation.", hint: "Use a token with 'write' scope or create a new one with appropriate permissions" } ``` ### Rate Limiting (1100-1199) #### `1101 - RATE_LIMIT_EXCEEDED` Too many requests in time window. ### Server Errors (1200-1299) #### `1201 - INTERNAL_SERVER_ERROR` General server error. #### `1202 - DATABASE_ERROR` Database operation failed. #### `1203 - CONFIGURATION_ERROR` System configuration issue. ### OAuth Errors (1300-1399) #### `1301 - GITHUB_NOT_LINKED` GitHub account not linked. #### `1302 - GITHUB_AUTH_FAILED` GitHub authentication failed. #### `1303 - OAUTH_STATE_MISMATCH` OAuth state verification failed. ## API Usage ### Import Error Utilities ```javascript import { ErrorCodes, ErrorMessages, getErrorByCode, createErrorResponse, logError } from 'mbkauthe'; ``` ### Get Error Details ```javascript import { getErrorByCode, ErrorCodes } from 'mbkauthe'; const error = getErrorByCode(ErrorCodes.INVALID_CREDENTIALS); console.log(error); // { // errorCode: 601, // message: "Invalid username or password", // userMessage: "The username or password you entered is incorrect...", // hint: "Check your spelling and make sure Caps Lock is off" // } ``` ### Create Error Response ```javascript import { createErrorResponse, ErrorCodes } from 'mbkauthe'; app.post('/login', async (req, res) => { // ... authentication logic if (!authenticated) { return res.status(401).json( createErrorResponse(401, ErrorCodes.INVALID_CREDENTIALS) ); } }); // Response: // { // success: false, // statusCode: 401, // errorCode: 601, // message: "The username or password you entered is incorrect...", // hint: "Check your spelling and make sure Caps Lock is off", // timestamp: "2025-12-03T12:00:00.000Z" // } ``` ### Add Custom Data ```javascript import { createErrorResponse, ErrorCodes } from 'mbkauthe'; return res.status(403).json( createErrorResponse(403, ErrorCodes.APP_NOT_AUTHORIZED, { appName: 'Admin Panel', requiredRole: 'SuperAdmin' }) ); // Response includes custom data: // { // success: false, // statusCode: 403, // errorCode: 605, // message: "You don't have permission to access this application.", // hint: "Contact your administrator if you believe this is an error", // timestamp: "2025-12-03T12:00:00.000Z", // appName: "Admin Panel", // requiredRole: "SuperAdmin" // } ``` ### Log Errors ```javascript import { logError, ErrorCodes } from 'mbkauthe'; // Log error with context logError('Login attempt', ErrorCodes.INVALID_CREDENTIALS, { username: 'john.doe', ip: req.ip, userAgent: req.headers['user-agent'] }); // Console output: // [mbkauthe] Login attempt: { // errorCode: 601, // message: 'Invalid username or password', // username: 'john.doe', // ip: '192.168.1.1', // userAgent: 'Mozilla/5.0...', // timestamp: '2025-12-03T12:00:00.000Z' // } ``` ## Error Response Format All error responses follow this structure: ```typescript { success: false, statusCode: number, errorCode: number, message: string, // User-friendly message hint: string, // How to resolve the error timestamp: string, // ISO 8601 timestamp ...customFields // Optional custom data } ``` ## Client-Side Error Handling ### JavaScript Example ```javascript async function login(username, password) { try { const response = await fetch('/mbkauthe/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await response.json(); if (!response.ok) { // Handle error based on error code switch (data.errorCode) { case 601: // INVALID_CREDENTIALS case 602: // USER_NOT_FOUND case 603: // INCORRECT_PASSWORD showError('Invalid username or password', data.hint); break; case 604: // ACCOUNT_INACTIVE showError('Account deactivated', data.hint); break; case 605: // APP_NOT_AUTHORIZED showError('Access denied', data.hint); redirectToHome(); break; case 1003: // INVALID_PASSWORD_LENGTH showFieldError('password', data.message, data.hint); break; default: showError(data.message, data.hint); } return; } // Handle successful login if (data.twoFactorRequired) { redirectTo2FA(); } else { redirectToDashboard(); } } catch (error) { showError('Network error', 'Please check your connection and try again'); } } function showError(message, hint) { const errorDiv = document.getElementById('error-message'); errorDiv.innerHTML = ` <div class="error"> <strong>${message}</strong> <p>${hint}</p> </div> `; } ``` ### React Example ```jsx import { ErrorCodes } from 'mbkauthe'; function LoginForm() { const [error, setError] = useState(null); const handleLogin = async (e) => { e.preventDefault(); try { const response = await fetch('/mbkauthe/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await response.json(); if (!response.ok) { setError({ code: data.errorCode, message: data.message, hint: data.hint }); return; } // Success handling... } catch (err) { setError({ message: 'Network error', hint: 'Please check your connection' }); } }; return ( <form onSubmit={handleLogin}> {error && ( <div className="alert alert-danger"> <strong>{error.message}</strong> {error.hint && <p className="hint">{error.hint}</p>} </div> )} {/* Form fields... */} </form> ); } ``` ## Custom Error Messages You can create custom error responses while maintaining the standard format: ```javascript import { createErrorResponse, sessVal } from 'mbkauthe'; app.post('/custom-action', sessVal, async (req, res) => { try { // Your logic... if (someCondition) { return res.status(400).json( createErrorResponse(400, 9999, { message: "Custom error message", hint: "How to fix this issue", additionalData: "Extra context" }) ); } } catch (error) { return res.status(500).json( createErrorResponse(500, 1201) ); } }); ``` ## Best Practices 1. **Use Error Codes**: Always use predefined error codes for consistency 2. **Log Errors**: Use `logError()` for server-side logging 3. **User-Friendly Messages**: Display `message` to users, not raw error codes 4. **Provide Hints**: Show `hint` to guide users on resolution 5. **Don't Expose Internals**: Avoid exposing system details in production 6. **Handle All Cases**: Have fallback error handling for unexpected errors 7. **Client-Side Validation**: Validate input before sending to prevent unnecessary errors 8. **Structured Logging**: Include context (username, IP, etc.) in logs ## Security Considerations 1. **Generic Messages**: For authentication, use generic messages to avoid user enumeration 2. **Rate Limiting**: Implement rate limiting to prevent brute force 3. **Logging**: Log all authentication failures for security monitoring 4. **Error Details**: Only expose detailed errors in development, not production 5. **Sensitive Data**: Never include passwords or tokens in error logs ## Examples ### Complete Login with Error Handling ```javascript router.post('/mbkauthe/api/login', async (req, res) => { const { username, password } = req.body; try { // Validation if (!username || !password) { logError('Login', ErrorCodes.MISSING_REQUIRED_FIELD); return res.status(400).json( createErrorResponse(400, ErrorCodes.MISSING_REQUIRED_FIELD) ); } if (username.length > 255) { logError('Login', ErrorCodes.INVALID_USERNAME_FORMAT, { username }); return res.status(400).json( createErrorResponse(400, ErrorCodes.INVALID_USERNAME_FORMAT) ); } if (password.length < 8) { logError('Login', ErrorCodes.INVALID_PASSWORD_LENGTH); return res.status(400).json( createErrorResponse(400, ErrorCodes.INVALID_PASSWORD_LENGTH) ); } // Authentication const user = await findUser(username); if (!user) { logError('Login', ErrorCodes.USER_NOT_FOUND, { username }); // Use generic message for security return res.status(401).json( createErrorResponse(401, ErrorCodes.INVALID_CREDENTIALS) ); } if (!await verifyPassword(password, user.password)) { logError('Login', ErrorCodes.INCORRECT_PASSWORD, { username }); return res.status(401).json( createErrorResponse(401, ErrorCodes.INCORRECT_PASSWORD) ); } if (!user.active) { logError('Login', ErrorCodes.ACCOUNT_INACTIVE, { username }); return res.status(403).json( createErrorResponse(403, ErrorCodes.ACCOUNT_INACTIVE) ); } // Success res.json({ success: true, sessionId: '...' }); } catch (error) { console.error(`[mbkauthe] Login error:`, error); return res.status(500).json( createErrorResponse(500, ErrorCodes.INTERNAL_SERVER_ERROR) ); } }); ``` ## Support For questions about error handling: - [GitHub Issues](https://github.com/MIbnEKhalid/mbkauthe/issues) - Email: support@mbktech.org