qgenutils
Version:
A security-first Node.js utility library providing authentication, HTTP operations, URL processing, validation, datetime formatting, and template rendering. Designed as a lightweight alternative to heavy npm packages with comprehensive error handling and
179 lines (170 loc) • 8.14 kB
JavaScript
/*
* Authentication Utility Module
*
* This module provides authentication utilities for applications using Passport.js
* authentication middleware. It focuses on checking authentication status and
* detecting configured authentication strategies.
*
* DESIGN PHILOSOPHY:
* - Security by default: Functions return false when authentication is uncertain
* - Graceful degradation: Handle missing Passport middleware without crashing
* - Strategy detection: Allow conditional features based on available auth methods
* - Error resilience: Authentication failures shouldn't break the entire request
*
* PASSPORT.JS INTEGRATION:
* Passport.js is a popular authentication middleware for Express.js that supports
* multiple authentication strategies (local, OAuth, SAML, etc.). These utilities
* work with Passport's standard API and patterns.
*
* GLOBAL PASSPORT ACCESS:
* These utilities read `global.passport` to inspect configured strategies.
* Storing the Passport instance globally lets any module check auth status
* without requiring dependency injection, which keeps helpers decoupled from
* Express initialization.
*
* FAIL-CLOSED RATIONALE:
* Any problem or misconfiguration should deny access rather than grant it.
* Returning `false` on errors prevents unauthorized exposure when the
* authentication state is uncertain.
*/
const { qerrors } = require('qerrors'); // integrate central error tracking
const logger = require('./logger'); // structured logger
/**
* Helper function to standardize authentication logging
* Centralization ensures consistent audit trails and easier debugging
*
* @param {string} functionName - Name of the calling function
* @param {*} input - Input parameter being processed
* @param {*} result - Result being returned
*/
function logAuthOperation(functionName, input, result) {
console.log(`${functionName} is running with ${input || 'none'}`); logger.debug(`${functionName} is running with ${input || 'none'}`); // log inputs for debugging context
console.log(`${functionName} is returning ${result}`); logger.debug(`${functionName} is returning ${result}`); // log outputs to trace decision making
}
/**
* Check Passport authentication status
*
* RATIONALE: Routes often gate protected resources behind authentication. Passport
* adds an isAuthenticated() method, but requests may omit the middleware or use
* alternate authentication flows. We defensively check and default to "deny" for
* security.
*
* IMPLEMENTATION DECISIONS:
* - Use double negation (!!) to convert truthy/falsy to strict boolean
* - Check for existence of isAuthenticated method before calling it
* - Default to false (unauthenticated) for security when in doubt
* - Log authentication attempts with user context for security auditing
*
* SECURITY CONSIDERATIONS:
* - Fail closed: When uncertain, assume user is NOT authenticated
* - Avoid throwing exceptions that could reveal authentication internals
* - Log all authentication checks for security monitoring
* - Handle edge cases where Passport middleware is missing
*
* TYPICAL USE CASES:
* - Gate route handlers to prevent anonymous access
* - Determine login state in view helpers for UI decisions
*
* WHY DOUBLE NEGATION (!!):
* req.isAuthenticated() might return truthy values that aren't strictly boolean.
* !! converts any truthy value to true and any falsy value to false.
* This ensures we always return a proper boolean type.
*
* EDGE CASES HANDLED:
* - req.isAuthenticated doesn't exist (Passport not configured)
* - req.isAuthenticated throws an exception
* - req object is malformed or null
* - User object exists but authentication state is unclear
*
* @param {object} req - Express request object (should have Passport methods attached)
* @returns {boolean} True if user is authenticated, false otherwise (fail-closed security)
*/
function checkPassportAuth(req) {
try { // begin auth state evaluation
const isAuthenticated = !!(req.isAuthenticated && req.isAuthenticated()); // call isAuthenticated if present else false then coerce to boolean
logAuthOperation('checkPassportAuth', req?.user?.username || 'guest', isAuthenticated); // record the check for auditing
return isAuthenticated; // return computed auth state
} catch (error) {
qerrors(error, 'checkPassportAuth', req); // capture any unexpected issues
return false; // fail closed on errors
}
}
/**
* Detect presence of GitHub OAuth strategy
*
* RATIONALE: Some interfaces display GitHub login options only when OAuth is
* configured. Checking Passport's strategies lets the UI adapt to available
* authentication methods without exposing configuration details.
*
* IMPLEMENTATION STRATEGY:
* - Access Passport's internal strategy registry
* - Check specifically for 'github' strategy by name
* - Convert result to strict boolean for consistency
* - Handle cases where Passport isn't available globally
*
* WHY CHECK STRATEGIES:
* Authentication strategies require configuration (client IDs, secrets, callback URLs).
* Just because the code supports GitHub OAuth doesn't mean it's properly configured.
* This function lets the UI adapt based on actual configuration.
*
* PASSPORT INTERNALS:
* Passport stores configured strategies in passport._strategies object.
* Each strategy has a name (key) and configuration object (value).
* This is an internal API but stable across Passport versions.
*
* ERROR HANDLING:
* - Return false if Passport isn't available (graceful degradation)
* - Return false if strategies object doesn't exist
* - Log errors for debugging configuration issues
* - Fail closed so misconfiguration never exposes OAuth endpoints
*
* TYPICAL USE CASES:
* - Show or hide GitHub login buttons in templates
* - Determine if GitHub-based routes should be active
*
* ALTERNATIVE APPROACHES CONSIDERED:
* - Environment variable checking - rejected because config might be dynamic
* - Strategy instantiation testing - rejected for performance reasons
* - Configuration file parsing - rejected for coupling reasons
*
* @returns {boolean} True if GitHub strategy is configured and available, false otherwise
* SECURITY: Function fails closed, returning false when configuration is uncertain
*/
function hasGithubStrategy() {
try { // attempt strategy detection
const passportObj = global.passport; // get Passport instance from global scope
if (!passportObj || !passportObj._strategies) { // confirm global passport and strategies registry exist
logAuthOperation('hasGithubStrategy', 'none', false); // note absence of GitHub strategy prerequisites
return false; // fail closed if prerequisites missing
}
const result = !!passportObj._strategies['github']; // boolean presence check for GitHub strategy
logAuthOperation('hasGithubStrategy', 'none', result); // log detection result for debugging
return result; // surface strategy availability to caller
} catch (err) {
qerrors(err, 'hasGithubStrategy'); // log unexpected errors
console.log('hasGithubStrategy has run resulting in a final value of failure'); logger.debug('hasGithubStrategy has run resulting in a final value of failure'); // manual error indicator
return false; // fail closed upon error
}
}
/*
* Module Export Strategy:
*
* We export both authentication functions because they serve different but
* related purposes:
*
* 1. checkPassportAuth - Runtime authentication state checking
* 2. hasGithubStrategy - Configuration/capability detection
*
* Both are essential for building adaptive user interfaces that respond
* appropriately to authentication state and available authentication methods.
*
* FUTURE ENHANCEMENTS:
* - Add functions to check other OAuth strategies (Google, Facebook, etc.)
* - Add role-based authorization checking
* - Add session expiration checking
* - Add multi-factor authentication support
*/
module.exports = { // expose utilities for external use
checkPassportAuth, // export runtime auth verifier
hasGithubStrategy // export GitHub strategy detector
};