Skip to content

feat: Add monitoring, metrics, and security features for multi-client authentication#42

Merged
Patrick-Ehimen merged 1 commit intomainfrom
feat/auth-monitoring
Dec 1, 2025
Merged

feat: Add monitoring, metrics, and security features for multi-client authentication#42
Patrick-Ehimen merged 1 commit intomainfrom
feat/auth-monitoring

Conversation

@Patrick-Ehimen
Copy link
Copy Markdown
Owner

@Patrick-Ehimen Patrick-Ehimen commented Nov 22, 2025

This PR implements comprehensive monitoring, metrics, and security features for the multi-client API key authentication system.

🚀 Features Added

MetricsCollector

  • Authentication and usage statistics tracking
  • Per-API-key usage tracking with secure key hashing
  • Performance metrics collection for authentication operations
  • Security event detection and alerting thresholds
  • Automatic cleanup of old data with configurable retention

AuthLogger

  • Structured logging for authentication events and audit trails
  • Secure logging without exposing API keys in plain text
  • Audit trail maintenance with sanitized data
  • Multiple log levels and export capabilities (JSON/CSV)
  • Automatic sensitive data sanitization in error messages

SecurityAlerter

  • Security event alerting for failed authentications and suspicious activity
  • Configurable alert thresholds and cooldown periods
  • Multiple notification handlers (console, webhook support)
  • Alert acknowledgment and management system
  • Pattern-based threat detection

MemoryManager

  • Memory cleanup utilities for sensitive data
  • Secure overwriting of sensitive data in memory with multiple passes
  • Automatic cleanup of API keys and sensitive fields
  • Buffer overwriting with cryptographically secure patterns

Summary by Sourcery

Add monitoring and security observability utilities for the authentication subsystem, including logging, metrics, alerting, and secure memory handling.

New Features:

  • Introduce a MetricsCollector to track authentication statistics, per-key usage, performance, and security events with retention and cleanup.
  • Add an AuthLogger for structured, sanitized authentication and security logging with an audit trail and export capabilities.
  • Provide a SecurityAlerter to generate, route, and manage security alerts with configurable severity, notifications, and cooldowns.
  • Add a MemoryManager and SensitiveData utilities to securely handle, overwrite, and clear sensitive values and buffers in memory.

Enhancements:

  • Expose new authentication observability and memory-management types and helpers from the auth module index for wider reuse.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Nov 22, 2025

Reviewer's Guide

Adds a full observability and security layer around multi-client API key authentication by introducing metrics collection, structured auth logging, security alerting, and in-memory secure data handling, and wiring these utilities into the auth module exports.

Sequence diagram for authentication with metrics, logging, and security alerts

sequenceDiagram
  actor "Client"
  participant "AuthService"
  participant "MetricsCollector"
  participant "AuthLogger"
  participant "SecurityAlerter"

  "Client"->>"AuthService": "Send authenticated request with API key"
  "AuthService"->>"AuthService": "Validate API key and produce AuthenticationResult"
  "AuthService"->>"MetricsCollector": "recordAuthentication(AuthenticationResult)"
  "MetricsCollector"-->>"AuthService": "Updated metrics and SecurityEvent list"

  "AuthService"->>"AuthLogger": "logAuthentication(AuthenticationResult, LogContext)"
  "AuthLogger"-->>"AuthService": "Log and audit trail updated"

  loop "For each new SecurityEvent from MetricsCollector"
    "AuthService"->>"SecurityAlerter": "processSecurityEvent(SecurityEvent)"
    "SecurityAlerter"->>"AuthLogger": "logSecurityEvent(SecurityEvent, LogContext)"
    "AuthLogger"-->>"SecurityAlerter": "Security log entry recorded"
    alt "Event should trigger alert"
      "SecurityAlerter"->>"SecurityAlerter": "evaluateEvent(SecurityEvent) and check cooldown"
      "SecurityAlerter"->>"ConsoleAlertHandler": "handleAlert(AlertNotification)"
      "ConsoleAlertHandler"-->>"SecurityAlerter": "Alert printed to console"
      opt "Webhook notifications enabled"
        "SecurityAlerter"->>"WebhookAlertHandler": "handleAlert(AlertNotification)"
        "WebhookAlertHandler"-->>"SecurityAlerter": "Alert sent via webhook"
      end
    end
  end
Loading

File-Level Changes

Change Details Files
Introduce a structured authentication logger with sanitization, audit trail, and export capabilities.
  • Define AuthLogLevel enum and interfaces for AuthLogEntry, AuditEntry, and AuthLoggerConfig with sensible defaults and sensitive field configuration.
  • Implement AuthLogger to log auth attempts, security events, tool executions, rate limit events, and cache operations, while maintaining bounded in-memory log and audit buffers.
  • Add sanitization routines for sensitive fields and error messages, along with JSON/CSV export, stats aggregation, and filtered retrieval APIs for logs and audits.
apps/mcp-server/src/auth/AuthLogger.ts
Add a metrics collection system for authentication performance, per-key usage, and security events with retention and cleanup.
  • Define AuthMetrics, KeyUsageStats, SecurityEvent and SecurityEventType, plus MetricsConfig with alert thresholds and retention/cleanup options.
  • Implement MetricsCollector to record AuthenticationResult data, cache hits/misses, security events, and per-key statistics, including failure rates and rate limit counts.
  • Provide alert evaluation helpers (overall/per-key failure rate), time-windowed security event queries, and periodic cleanup of stale key statistics and events.
apps/mcp-server/src/auth/MetricsCollector.ts
Introduce a security alerting subsystem with pluggable handlers and alert lifecycle management.
  • Define AlertSeverity, AlertConfig, AlertNotification, and AlertHandler plus default configuration with thresholds and cooldowns.
  • Implement SecurityAlerter that consumes SecurityEvent objects, evaluates them into alerts, handles cooldown logic, and stores/filters/acknowledges alerts in memory.
  • Provide built-in ConsoleAlertHandler and WebhookAlertHandler for console and HTTP webhook notifications, using the shared AuthLogger for alert logging when provided.
apps/mcp-server/src/auth/SecurityAlerter.ts
Add a memory management utility for secure handling and cleanup of sensitive data in memory.
  • Define MemoryManagerConfig and DEFAULT_MEMORY_CONFIG, and implement SensitiveData wrapper that auto-clears values after optional TTL with multi-pass overwrite.
  • Implement MemoryManager with helpers to create SensitiveData, securely overwrite strings/buffers and object fields, schedule and execute cleanup callbacks, and manage a secure execution context.
  • Expose a global memoryManager instance and convenience functions createSensitive, clearSensitiveFields, and withSecureContext for use by auth-related code.
apps/mcp-server/src/auth/MemoryManager.ts
Wire new monitoring and security utilities into the auth module public API.
  • Export MetricsCollector, AuthLogger, SecurityAlerter, MemoryManager, and related helper functions from the auth index so they are available to consumers.
  • Export the corresponding type definitions (metrics, logging, alerting, and memory configs) to support typed integration in other parts of the system.
apps/mcp-server/src/auth/index.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and found some issues that need to be addressed.

  • In SensitiveData.clear you hardcode DEFAULT_MEMORY_CONFIG.overwriteIterations instead of using the active MemoryManager configuration, which can lead to surprising behavior when overwriteIterations is customized; consider passing the config into SensitiveData or delegating the overwrite logic back to MemoryManager.
  • MemoryManager.createSecureContext relies on mutating global variables by name for cleanup, which is brittle and may either miss actual sensitive data or accidentally clobber unrelated globals; it would be safer to restrict cleanup to explicitly passed objects/fields or return an explicit cleanup function to be called by the caller.
  • AuthLogger.sanitizeDetails only redacts sensitiveFields at the top level of the details object, so nested structures can still leak sensitive data; consider making the sanitization recursive over nested objects/arrays to ensure sensitive keys are consistently redacted.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In SensitiveData.clear you hardcode DEFAULT_MEMORY_CONFIG.overwriteIterations instead of using the active MemoryManager configuration, which can lead to surprising behavior when overwriteIterations is customized; consider passing the config into SensitiveData or delegating the overwrite logic back to MemoryManager.
- MemoryManager.createSecureContext relies on mutating global variables by name for cleanup, which is brittle and may either miss actual sensitive data or accidentally clobber unrelated globals; it would be safer to restrict cleanup to explicitly passed objects/fields or return an explicit cleanup function to be called by the caller.
- AuthLogger.sanitizeDetails only redacts sensitiveFields at the top level of the details object, so nested structures can still leak sensitive data; consider making the sanitization recursive over nested objects/arrays to ensure sensitive keys are consistently redacted.

## Individual Comments

### Comment 1
<location> `apps/mcp-server/src/auth/AuthLogger.ts:395-398` </location>
<code_context>
+  /**
+   * Sanitize sensitive information from details
+   */
+  private sanitizeDetails(details: Record<string, unknown>): Record<string, unknown> {
+    const sanitized = { ...details };
+
+    for (const field of this.config.sensitiveFields) {
+      if (sanitized[field]) {
+        sanitized[field] = "[REDACTED]";
</code_context>

<issue_to_address>
**issue (bug_risk):** Sanitization skips falsy values for sensitive fields, which may leave some sensitive data unredacted.

Because the condition uses `if (sanitized[field])`, only truthy values are redacted. Falsy values like `""`, `0`, or `false` in `sensitiveFields` will bypass sanitization and may expose sensitive data. Instead, check for the field’s presence (e.g., `if (field in sanitized)` or using `hasOwnProperty`) and always redact when present, regardless of its value.
</issue_to_address>

### Comment 2
<location> `apps/mcp-server/src/auth/AuthLogger.ts:466-475` </location>
<code_context>
+  /**
+   * Export logs as CSV format
+   */
+  private exportAsCSV(): string {
+    const headers = ["timestamp", "level", "event", "keyHash", "requestId", "toolName", "details"];
+    const rows = [headers.join(",")];
+
+    for (const entry of this.logEntries) {
+      const row = [
+        entry.timestamp,
+        entry.level,
+        entry.event,
+        entry.keyHash,
+        entry.requestId || "",
+        entry.toolName || "",
+        JSON.stringify(entry.sanitizedDetails || entry.details).replace(/"/g, '""'),
+      ];
+      rows.push(row.join(","));
+    }
+
</code_context>

<issue_to_address>
**issue (bug_risk):** CSV export does not properly escape or quote fields, which can produce malformed CSV output.

Currently only `details` is escaped and all fields are joined with commas unquoted. Any field containing commas or newlines (e.g. `toolName`, `event`, `keyHash`) will produce invalid CSV and may break parsers. Please either quote every field and escape internal quotes for all columns, or use a CSV utility to handle this correctly.
</issue_to_address>

### Comment 3
<location> `apps/mcp-server/src/auth/MemoryManager.ts:8-11` </location>
<code_context>
+/**
+ * Memory manager configuration
+ */
+export interface MemoryManagerConfig {
+  enabled: boolean;
+  overwriteIterations: number;
+  clearIntervalMs: number;
+}
+
</code_context>

<issue_to_address>
**suggestion:** clearIntervalMs is defined in the MemoryManagerConfig but not used anywhere.

This unused setting is misleading. Please either integrate `clearIntervalMs` into a periodic cleanup mechanism (e.g., using it to schedule `executeCleanup`) or remove it from the config so it doesn’t suggest behavior that isn’t implemented.
</issue_to_address>

### Comment 4
<location> `apps/mcp-server/src/auth/MemoryManager.ts:71` </location>
<code_context>
      const length = this._value.length;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Prefer object destructuring when accessing and using properties. ([`use-object-destructuring`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/use-object-destructuring))

```suggestion
      const {length} = this._value;
```

<br/><details><summary>Explanation</summary>Object destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the [Airbnb Javascript Style Guide](https://airbnb.io/javascript/#destructuring--object)
</details>
</issue_to_address>

### Comment 5
<location> `apps/mcp-server/src/auth/MemoryManager.ts:90` </location>
<code_context>
    const value = this.value;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Prefer object destructuring when accessing and using properties. ([`use-object-destructuring`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/use-object-destructuring))

```suggestion
    const {value} = this;
```

<br/><details><summary>Explanation</summary>Object destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the [Airbnb Javascript Style Guide](https://airbnb.io/javascript/#destructuring--object)
</details>
</issue_to_address>

### Comment 6
<location> `apps/mcp-server/src/auth/MemoryManager.ts:156` </location>
<code_context>
    const length = str.length;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Prefer object destructuring when accessing and using properties. ([`use-object-destructuring`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/use-object-destructuring))

```suggestion
    const {length} = str;
```

<br/><details><summary>Explanation</summary>Object destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the [Airbnb Javascript Style Guide](https://airbnb.io/javascript/#destructuring--object)
</details>
</issue_to_address>

### Comment 7
<location> `apps/mcp-server/src/auth/MemoryManager.ts:263` </location>
<code_context>
      const length = value.length;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Prefer object destructuring when accessing and using properties. ([`use-object-destructuring`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/use-object-destructuring))

```suggestion
      const {length} = value;
```

<br/><details><summary>Explanation</summary>Object destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the [Airbnb Javascript Style Guide](https://airbnb.io/javascript/#destructuring--object)
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +395 to +398
private sanitizeDetails(details: Record<string, unknown>): Record<string, unknown> {
const sanitized = { ...details };

for (const field of this.config.sensitiveFields) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Sanitization skips falsy values for sensitive fields, which may leave some sensitive data unredacted.

Because the condition uses if (sanitized[field]), only truthy values are redacted. Falsy values like "", 0, or false in sensitiveFields will bypass sanitization and may expose sensitive data. Instead, check for the field’s presence (e.g., if (field in sanitized) or using hasOwnProperty) and always redact when present, regardless of its value.

Comment on lines +466 to +475
private exportAsCSV(): string {
const headers = ["timestamp", "level", "event", "keyHash", "requestId", "toolName", "details"];
const rows = [headers.join(",")];

for (const entry of this.logEntries) {
const row = [
entry.timestamp,
entry.level,
entry.event,
entry.keyHash,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): CSV export does not properly escape or quote fields, which can produce malformed CSV output.

Currently only details is escaped and all fields are joined with commas unquoted. Any field containing commas or newlines (e.g. toolName, event, keyHash) will produce invalid CSV and may break parsers. Please either quote every field and escape internal quotes for all columns, or use a CSV utility to handle this correctly.

Comment on lines +8 to +11
export interface MemoryManagerConfig {
enabled: boolean;
overwriteIterations: number;
clearIntervalMs: number;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: clearIntervalMs is defined in the MemoryManagerConfig but not used anywhere.

This unused setting is misleading. Please either integrate clearIntervalMs into a periodic cleanup mechanism (e.g., using it to schedule executeCleanup) or remove it from the config so it doesn’t suggest behavior that isn’t implemented.

@Patrick-Ehimen Patrick-Ehimen merged commit 833e35b into main Dec 1, 2025
1 check passed
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.

1 participant