Skip to content

feat: Add logging support to Management API client#1242

Closed
fern-api[bot] wants to merge 4 commits intomasterfrom
fern-bot/2025-11-06T06-53Z
Closed

feat: Add logging support to Management API client#1242
fern-api[bot] wants to merge 4 commits intomasterfrom
fern-bot/2025-11-06T06-53Z

Conversation

@fern-api
Copy link
Copy Markdown
Contributor

@fern-api fern-api bot commented Nov 6, 2025

Changes

This PR adds comprehensive logging support to the Management API client through Fern regeneration. The changes include:

New Logging Framework:

  • Added new Logger class with level-based logging (debug, info, warn, error)
  • Added ConsoleLogger implementation for console output
  • Added LogConfig interface for logger configuration
  • Added logging exports to the core API

HTTP Request Logging:

  • Integrated logging into the Fetcher with automatic request/response logging
  • Implemented security-focused redaction for sensitive data:
    • Headers (authorization, api-key, cookies, tokens)
    • URL credentials (user:pass@host)
    • Query parameters (token, key, password, secret, session)
  • Added performance optimizations for query parameter redaction with fast-path checks
  • Logs include method, URL, headers, status codes, and error details

API Integration:

  • Added logging parameter to BaseClientOptions interface
  • Propagated logging configuration through all Management API endpoints (Actions, Branding, Clients, Connections, etc.)
  • All API calls now support optional logging configuration

Configuration:

  • Moved dependencies from devDependencies to dependencies in package.json (uuid, jose, auth0-legacy)
  • Added .fern/ to .fernignore
  • Logging is silent by default (silent: true) to avoid breaking existing implementations

Usage Examples:

import { ManagementClient, logging } from 'auth0';

// Example 1: Enable debug logging with console output
const management = new ManagementClient({
  domain: 'tenant.auth0.com',
  clientId: 'client-id',
  clientSecret: 'client-secret',
  logging: {
    level: logging.LogLevel.Debug,
    silent: false
  }
});

// Example 2: Use a custom logger implementation
class CustomLogger implements logging.ILogger {
  debug(message: string, ...args: unknown[]) {
    // Custom debug logging logic (e.g., send to external service)
    console.debug('[AUTH0]', message, ...args);
  }
  info(message: string, ...args: unknown[]) {
    console.info('[AUTH0]', message, ...args);
  }
  warn(message: string, ...args: unknown[]) {
    console.warn('[AUTH0]', message, ...args);
  }
  error(message: string, ...args: unknown[]) {
    console.error('[AUTH0]', message, ...args);
  }
}

const managementWithCustomLogger = new ManagementClient({
  domain: 'tenant.auth0.com',
  clientId: 'client-id',
  clientSecret: 'client-secret',
  logging: {
    level: logging.LogLevel.Info,
    logger: new CustomLogger(),
    silent: false
  }
});

// Example 3: Use the built-in ConsoleLogger directly
const managementWithConsoleLogger = new ManagementClient({
  domain: 'tenant.auth0.com',
  clientId: 'client-id',
  clientSecret: 'client-secret',
  logging: {
    level: logging.LogLevel.Warn,
    logger: new logging.ConsoleLogger(),
    silent: false
  }
});

// When enabled, logs will show:
// - HTTP request details (method, redacted URL, headers)
// - Response status codes
// - Error information
// - All sensitive data (tokens, passwords, keys) is automatically redacted

References

This is a Fern-generated update that adds logging infrastructure to support debugging and monitoring of Management API calls.

Testing

  • This change adds unit test coverage (Fern-generated tests)
  • This change adds integration test coverage (existing tests pass)

Testing approach:

  • All existing tests pass without modification (logging is silent by default)
  • New logging functionality can be tested by providing logging configuration:
const management = new ManagementClient({
  domain: 'tenant.auth0.com',
  clientId: 'client-id',
  clientSecret: 'client-secret',
  logging: {
    level: LogLevel.Debug,
    silent: false
  }
});
  • Sensitive data redaction has been implemented to protect credentials in logs
  • Fast-path optimizations ensure minimal performance impact when logging is disabled

Checklist

@fern-api fern-api bot requested a review from a team as a code owner November 6, 2025 06:53
@codecov
Copy link
Copy Markdown

codecov bot commented Nov 6, 2025

Codecov Report

❌ Patch coverage is 22.97297% with 114 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.74%. Comparing base (da3aa87) to head (1024238).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
src/management/core/fetcher/Fetcher.ts 8.79% 83 Missing ⚠️
src/management/core/logging/logger.ts 36.73% 31 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1242      +/-   ##
==========================================
- Coverage   78.19%   77.74%   -0.45%     
==========================================
  Files         354      359       +5     
  Lines       17742    17892     +150     
  Branches     9413     9456      +43     
==========================================
+ Hits        13874    13911      +37     
- Misses       3868     3981     +113     
Flag Coverage Δ
alltests 77.74% <22.97%> (-0.45%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@developerkunal developerkunal changed the title 🌿 Fern Regeneration -- November 6, 2025 feat: Add logging support to Management API client Nov 6, 2025
- Export logging namespace from src/management/index.ts
- Add comprehensive logging documentation to README.md
- Include examples for debug logging, custom loggers, and ConsoleLogger
- Document log levels and security features (automatic redaction)
kushalshit27
kushalshit27 previously approved these changes Nov 6, 2025
tanya732
tanya732 previously approved these changes Nov 6, 2025
@developerkunal developerkunal dismissed stale reviews from tanya732 and kushalshit27 via 1024238 November 6, 2025 09:11
@gyaneshgouraw-okta
Copy link
Copy Markdown
Contributor

@claude

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 6, 2025

Claude finished @gyaneshgouraw-okta's task —— View job


Overall Assessment

❌ This PR introduces a useful logging feature but has critical issues that must be fixed before merging, particularly a logic bug that inverts the log level filtering behavior.

Critical Issues:

  1. Log level comparison is inverted (src/management/core/logging/logger.ts:105) - This will cause Error-level loggers to output Debug messages and Debug-level loggers to suppress Error messages
  2. Overly broad sensitive parameter detection (src/management/core/fetcher/Fetcher.ts:167) - The auth substring check will incorrectly redact legitimate parameters like ?author=john

Security Concerns:

  • Missing several common sensitive headers in the redaction list
  • Response headers are not redacted before logging (may leak Set-Cookie and other sensitive data)
  • URL credential redaction doesn't handle edge cases with multiple @ symbols
  • Silent error swallowing in URL decoding could mask issues

Performance Issues:

  • Logger instance created on every request instead of being reused
  • Unnecessary object allocations even when logging is disabled

Code Quality:

  • Redundant null check in createLogger function
  • Missing request/response body logging makes debugging difficult
  • Documentation doesn't clarify that logging infrastructure always runs (just silently)

Positive Aspects:

  • Good security-first approach with redaction
  • Comprehensive coverage across all API endpoints
  • Backward compatible (silent by default)
  • Well-documented with clear examples

The logging feature is valuable, but the inverted log level logic is a blocker that will cause incorrect behavior in production.


Job Run • Branch: fern-bot/2025-11-06T06-53Z

* @returns True if the level should be logged
*/
public shouldLog(level: LogLevel): boolean {
return !this.silent && this.level >= logLevelMap[level];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic in shouldLog is inverted. Currently, it checks this.level >= logLevelMap[level], which means a higher level number (e.g., Error=4) will output logs for lower levels (e.g., Debug=1). This is backwards.

For example:

  • If this.level = Error (4) and we call debug() (level=1), the check becomes 4 >= 1 → true, so debug logs appear
  • If this.level = Debug (1) and we call error() (level=4), the check becomes 1 >= 4 → false, so error logs are suppressed

The comparison should be <= instead of >=.


if (!hasSensitive) {
return url; // Early exit - no sensitive params
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fast-path check includes lower.includes("auth") which will incorrectly flag many legitimate query parameters as sensitive. For example:

  • ?author=john would trigger redaction
  • ?authenticate_user=false would trigger redaction
  • ?authorization_type=implicit would trigger redaction

Consider removing lower.includes("auth") or making it more specific (e.g., lower.includes("auth_token") or lower.includes("auth-token")).

const decodedKey = decodeURIComponent(key);
shouldRedact = SENSITIVE_QUERY_PARAMS.has(decodedKey.toLowerCase());
} catch {}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL decoding attempt catches all errors silently without any logging or handling. This could mask legitimate issues. Additionally, URL-encoded keys should be checked before decoding to avoid unnecessary decoding attempts.

Consider checking if URL encoding exists before attempting to decode, and at minimum log caught errors when debug logging is enabled.

);

if (atIndex < firstDelimiter) {
url = `${url.slice(0, afterProtocol)}[REDACTED]@${url.slice(atIndex + 1)}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL redaction logic only redacts credentials in the authority section (user:pass@host) but doesn't handle edge cases:

  1. Empty credentials (e.g., http://:password@host or http://user:@host)
  2. Multiple @ symbols (e.g., http://user:pass@word@host)

The current logic would fail to properly redact case 2, as it would only redact up to the first @.

url: redactUrl(url),
headers: redactHeaders(headers),
queryParameters: redactQueryParameters(args.queryParameters),
hasBody: requestBody != null,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging the request body content is missing. For debugging purposes, it would be valuable to log whether a body exists and potentially its size or a redacted version of its content. This would help diagnose issues with malformed requests.

if (config instanceof Logger) {
return config;
}
config = config ?? {};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null coalescing assignment config = config ?? {} on line 192 is redundant since line 186 already checks if config == null and returns early. This line will never execute with a null config.

}
}

const SENSITIVE_HEADERS = new Set([
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing sensitive headers in the redaction list:

  • x-auth-token and x-api-key are included, but common variants are missing:
    • bearer (standalone Bearer tokens)
    • x-access-token
    • x-session-token
    • x-refresh-token
    • x-client-secret
    • authentication (some APIs use this instead of Authorization)

@@ -106,13 +256,29 @@ export async function fetcherImpl<R = unknown>(args: Fetcher.Args): Promise<APIR
);

if (response.status >= 200 && response.status < 400) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response headers should be redacted before logging for security. Response headers may contain sensitive information like:

  • Set-Cookie headers with session tokens
  • X-RateLimit-* headers that could reveal API usage patterns
  • Custom authentication headers

Consider redacting response headers similar to how request headers are redacted.

}
return {
ok: true,
body: (await getResponseBody(response, args.responseType)) as R,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response body is never logged or included in debug output. While this is good for security (avoiding logging sensitive data), it makes debugging difficult. Consider:

  1. Adding a configuration option to enable/disable body logging
  2. Logging body size/type information
  3. Providing a sanitized preview for non-sensitive content types

### Logging

The SDK provides built-in logging support to help with debugging and monitoring API requests. Logging is disabled by default to avoid noise in production environments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states logging is "disabled by default" but technically it's "silent by default" (silent: true). The logging infrastructure is always instantiated, it just doesn't output anything. Consider clarifying this distinction in the docs, as users might think there's zero performance overhead when disabled.

});
const fetchFn = args.fetchFn ?? (await getFetchFn());
const headers = await getHeaders(args);
const logger = createLogger(args.logging);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logger is created on every request, even when logging is disabled. This creates unnecessary object allocation overhead. Consider:

  1. Creating the logger once during client initialization and reusing it
  2. Adding an early-exit check if args.logging is undefined and silent is true
  3. Caching the logger instance per configuration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants