Skip to content

feat: add structured authentication event logging (#1104)#1289

Merged
ggfevans merged 4 commits intomainfrom
feat/1104-auth-event-logging
Feb 25, 2026
Merged

feat: add structured authentication event logging (#1104)#1289
ggfevans merged 4 commits intomainfrom
feat/1104-auth-event-logging

Conversation

@ggfevans
Copy link
Collaborator

@ggfevans ggfevans commented Feb 20, 2026

User description

Summary

  • New api/src/auth-logger.ts module for structured JSON auth event logging
  • Events: login success/failure, logout, session invalid, authorization denied
  • Secret redaction — tokens, cookies, session IDs never appear in logs
  • JSON lines to stdout for Docker/syslog/SIEM forwarding
  • Integrated into auth gate, authorization middleware, logout and auth check handlers

Files Changed

  • api/src/auth-logger.ts — new structured logger module
  • api/src/auth-logger.test.ts — 11 tests for events, redaction, integration
  • api/src/security.ts — auth gate logs session.invalid on rejection
  • api/src/authorization.ts — logs auth.denied on non-admin write
  • api/src/app.ts — logs login success/failure on auth check, logout

Test plan

  • redactHeaders strips sensitive fields (Authorization, Cookie, etc.)
  • extractRequestContext extracts method, path, IP
  • emitAuthEvent writes valid JSON to stdout
  • No raw tokens or session values in emitted events
  • Integration: auth.session.invalid on anonymous API request
  • Integration: auth.logout on POST /auth/logout
  • Integration: auth.denied on non-admin write attempt
  • Integration: auth.login.success on valid auth check
  • Integration: auth.login.failure on invalid auth check
  • Integration: raw session tokens never appear in log output
  • All 85 API tests pass

Closes #1104

🤖 Generated with Claude Code


CodeAnt-AI Description

Emit structured, redacted authentication event logs (JSON) to stdout

What Changed

  • The server now writes newline-delimited JSON auth events to stdout for auth.login.success, auth.login.failure, auth.logout, auth.session.invalid, and auth.denied
  • Each event includes timestamp, HTTP method and path, and pseudonymized subject and IP; raw tokens, cookies, and session IDs are never present in logs
  • Pseudonyms are derived from a configurable hash key (falls back to a key derived from the session secret or an ephemeral per-process key) so identifiers can be stable when configured
  • Auth logging is integrated into auth check, logout, auth gate rejection, and admin-authorization failures; 11 tests cover emission, redaction, pseudonymization, and integrations

Impact

✅ Clearer audit trails for authentication events
✅ Fewer leaked secrets in logs
✅ Stable pseudonymized identifiers when hash key configured

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Add auth-logger module emitting structured JSON lines to stdout for
Docker/self-hosted log forwarding with secret redaction.

Events logged:
- auth.login.success — valid session on /auth/check
- auth.login.failure — invalid/missing session on /auth/check
- auth.logout — POST /auth/logout with valid session
- auth.session.invalid — auth gate rejects anonymous request
- auth.denied — authorization middleware blocks non-admin write

Each event includes timestamp, event type, request method/path, and
optionally the subject (email) and denial reason. Sensitive data
(tokens, cookies, session IDs) is never included in log output.

- New api/src/auth-logger.ts with emitAuthEvent(), logAuthEvent(),
  redactHeaders(), and extractRequestContext()
- Integrated into auth gate (security.ts), authorization middleware,
  logout handler, and auth check handler (app.ts)
- 11 new tests covering event emission, redaction, and integration

Fixes #1104

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 20, 2026

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

📝 Walkthrough

Walkthrough

Adds a new auth-event logger that emits redacted, optionally pseudonymized JSON-line auth events to stdout and wires logging into auth/authorization/security flows (login success/failure, logout, session invalid, denied) with configurable HMAC hash key handling.

Changes

Cohort / File(s) Summary
Auth logger module & tests
api/src/auth-logger.ts, api/src/auth-logger.test.ts
New auth-event logger: redacts sensitive headers, pseudonymizes identifiers via HMAC with configurable key, emits JSON-line events to stdout, and includes comprehensive unit/integration tests.
App integration
api/src/app.ts
Initializes auth-log hash key on startup by calling configureAuthLogHashKey(...).
Authorization middleware
api/src/authorization.ts
Calls safeLogAuthEvent("auth.denied", ...) when a non-admin attempts restricted access (log side-effect added).
Security config & auth-gate
api/src/security.ts, api/src/security.test.ts
Adds authLogHashKey to ApiSecurityConfig, derives/validates/overrides hash key (including ephemeral fallback), and logs auth.session.invalid for missing/invalid sessions; tests added for key derivation/validation.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant App as App / Middleware
  participant AuthLogger as Auth Logger (auth-logger.ts)
  participant Stdout as Stdout

  Client->>App: HTTP request (may include session/cookie)
  alt missing or invalid session
    App->>AuthLogger: logAuthEvent("auth.session.invalid", request, { reason })
  else authenticated
    App->>AuthLogger: logAuthEvent("auth.login.success" / "auth.login.failure" / "auth.logout" / "auth.denied", request, { subject?, reason? })
  end
  AuthLogger->>Stdout: emitAuthEvent -> write redacted, pseudonymized JSON line
  App->>Client: HTTP response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

size:L

Poem

🐇
I nibble headers, hide the crumbs of keys,
I hash the hops and hush the IPs.
Events go out as tidy, silent art —
footprints of logins, but secrets stay apart. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add structured authentication event logging (#1104)' clearly and concisely describes the main change: introducing a new authentication event logging system. It is specific, readable, and directly reflects the primary objective of the PR.
Description check ✅ Passed The description comprehensively relates to the changeset, detailing the new auth-logger module, event types, redaction mechanisms, integration points, and test coverage. It clearly explains what changed and why.
Linked Issues check ✅ Passed All acceptance criteria from linked issue #1104 are met: the PR implements all required event types (login success/failure, logout, session.invalid, auth.denied) [#1104], includes timestamp and request context [#1104], redacts sensitive data [#1104], emits JSON lines to stdout [#1104], and includes unit and integration tests verifying emission and redaction [#1104].
Out of Scope Changes check ✅ Passed All code changes are directly aligned with the stated objectives of implementing structured authentication event logging. No out-of-scope modifications were detected; changes span auth logger implementation, security integration, authorization logging, and comprehensive test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/1104-auth-event-logging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai bot added the size:L This PR changes 100-499 lines, ignoring generated files label Feb 20, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 20, 2026

Sequence Diagram

Shows how the app emits structured JSON auth events for key authentication and authorization outcomes (login success/failure, logout, session invalidation, and authorization denial) — the core change in this PR.

sequenceDiagram
    participant Client
    participant API
    participant AuthLogger

    Client->>API: GET /auth/check
    API->>API: Resolve session from cookie
    alt Session valid
        API->>AuthLogger: logAuthEvent("auth.login.success", req, {subject})
        AuthLogger-->>API: (JSON line to stdout)
        API-->>Client: 200 OK
    else Session missing/invalid
        API->>AuthLogger: logAuthEvent("auth.login.failure", req, {reason})
        AuthLogger-->>API: (JSON line to stdout)
        API-->>Client: 401 Unauthorized
    end

    Client->>API: POST /auth/logout (with session cookie)
    API->>API: Invalidate session
    API->>AuthLogger: logAuthEvent("auth.logout", req, {subject})
    AuthLogger-->>API: (JSON line to stdout)
    API-->>Client: 204 No Content

    Client->>API: PUT /layouts/* (state-changing request)
    API->>API: Authorization middleware checks role
    alt Not admin
        API->>AuthLogger: logAuthEvent("auth.denied", req, {subject, reason})
        AuthLogger-->>API: (JSON line to stdout)
        API-->>Client: 403 Forbidden
    end

    Client->>API: Any request without valid session (auth gate)
    API->>AuthLogger: logAuthEvent("auth.session.invalid", req, {reason})
    AuthLogger-->>API: (JSON line to stdout)
    API-->>Client: 401 Unauthorized
Loading

Generated by CodeAnt AI

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 20, 2026

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Sensitive logging
    The middleware now calls logAuthEvent with the raw Request object. If the logger doesn't fully sanitize/redact all headers and request material, this could expose cookies, Authorization headers, or session tokens in logs. Verify the logger's sanitization covers all header names and body content paths, and prefer passing a minimal request context.

  • Log timing & content
    The middleware logs auth.denied using claims.sub and claims.role. Ensure claims.sub cannot contain secret/session-like values in all flows. Also confirm the log event doesn't accidentally include request headers or cookies in other call sites (defensive review of future changes).

  • Redaction scope
    The logger currently never includes headers in emitted events and redactHeaders only accepts Record<string,string>. If future callers include headers or pass a Headers object, sensitive values might be logged unless headers are normalized and redacted consistently. Validate all call sites and consider expanding redactHeaders to accept/normalize different header shapes (Headers, HeadersInit) and to be applied when building log payloads.

  • Logging side-effects
    logAuthEvent is invoked synchronously inside the auth gate with no try/catch. If the logger throws, it could break auth middleware and alter request flow (e.g., prevent redirects or JSON responses). Consider making logging fail-safe.

  • Logging robustness
    emitAuthEvent calls JSON.stringify and process.stdout.write directly. If JSON.stringify throws (unlikely but possible if event contains unexpected values) or stdout.write fails, the app could surface an unhandled exception. Consider making emitAuthEvent resilient (try/catch, safe serialization, fallback logging).

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 20, 2026

CodeAnt AI finished reviewing your PR.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/src/auth-logger.test.ts`:
- Around line 1-8: The test imports unused symbols `mock` and `logAuthEvent`
which triggers the `@typescript-eslint/no-unused-vars` error; update the import
list in auth-logger.test.ts to remove `mock` and/or `logAuthEvent` (or
alternatively use them explicitly in the test if the intent was to exercise them
directly) so only actually used symbols remain (keep `beforeEach`, `describe`,
`expect`, `it`, `spyOn` and remove `mock` and `logAuthEvent` unless you add a
direct call to `logAuthEvent` or use `mock` in a test).
- Around line 104-314: Install and restore the stdout spy in
beforeEach/afterEach instead of per-test to avoid leakage: in both describe
blocks ("emitAuthEvent" and "auth event integration") declare a let writeSpy; in
beforeEach set writeSpy = spyOn(process.stdout, "write").mockImplementation(()
=> true); and in afterEach call writeSpy.mockRestore(); then remove per-test
mockRestore() calls and any duplicate spy setup inside individual tests (leave
only the emits and assertions that read writeSpy.mock.calls). This keeps the
unique symbol spyOn(process.stdout, "write") managed safely across tests.

In `@api/src/auth-logger.ts`:
- Around line 15-23: AuthEvent currently logs raw personal identifiers (subject
from claims.sub and ip from x-real-ip); replace those plain values with
pseudonymized hashes at emit time by adding a helper (e.g.,
pseudonymizeIdentifier(value: string): string) that computes a stable SHA-256
(or HMAC-SHA256 with a config-held key/salt) and use it when populating
AuthEvent.subject and AuthEvent.ip so logs contain non-reversible identifiers
while remaining linkable for audit; update any code paths that create AuthEvent
(references: AuthEvent, subject, ip, claims.sub, x-real-ip) to call that helper
before logging and ensure the hashing key/salt is configurable and protected.

Follow up on CodeRabbit review for #1104 auth event logging:\n- pseudonymize subject/ip identifiers with keyed, namespaced hashes\n- wire configurable auth log hash key from security config\n- derive log hash key from session secret context or generate ephemeral fallback\n- tighten hash key validation and add config diagnostics\n- refactor stdout spy lifecycle and auth logger tests\n\nFixes #1104
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 20, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Feb 20, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 20, 2026

CodeAnt AI Incremental review completed.

coderabbitai[bot]
coderabbitai bot previously requested changes Feb 20, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/src/app.ts (1)

119-134: ⚠️ Potential issue | 🟡 Minor

Auth check logging is well-placed with correct event semantics.

auth.login.failure on missing session and auth.login.success on valid session are logged at the right points. The raw claims.sub is correctly passed to logAuthEvent, with pseudonymization handled by emitAuthEvent downstream.

Note: the same reliability concern raised on security.ts line 1120 applies here — an exception from logAuthEvent would prevent the 401 response or the 204+cookie refresh from being sent. Consider wrapping in try/catch for the same reason.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/app.ts` around lines 119 - 134, The logAuthEvent calls around the
authentication check (after resolveAuthenticatedSessionClaims) can throw and
block sending the 401 or success response; wrap both invocations of logAuthEvent
(the failure branch and the success branch where you pass claims.sub) in
try/catch blocks so any logging error is caught and does not prevent returning
the JSON 401 or proceeding with the 204+cookie refresh; ensure the catch either
swallows or records the logging error safely (e.g., fallback to console.error or
a non-throwing logger) so response flow from resolveAuthenticatedSessionClaims
remains unaffected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/src/auth-logger.test.ts`:
- Around line 185-188: The test reads from authEvents using .some() then calls
authEvents.find(...) and accesses properties on the result (event) without null
checking; change each pattern (e.g., the block with authEvents.some(...) and
const event = authEvents.find(...)) to either assert the find result is defined
before accessing properties (e.g., const event = authEvents.find(...);
expect(event).toBeDefined(); /* then access event!.reason */) or collapse to a
single assertion that directly expects the found object (e.g., const event =
authEvents.find(...); expect(event).toMatchObject({ reason: "missing or invalid
session cookie", path: "/api/layouts" })); apply the same guard/non-null
assertion fix to the other occurrences noted (the blocks around lines referenced
for authEvents).
- Around line 170-189: Create a small shared helper (e.g., extractAuthEvents)
that accepts the test spy (writeSpy) and returns parsed auth-related event
objects by mapping writeSpy.mock.calls, JSON.parse-ing each call, and filtering
where e?.event?.startsWith("auth."); replace the repeated map→parse→filter
blocks in the tests (references: the test that asserts "auth.session.invalid"
and the other duplicated blocks) with calls to extractAuthEvents(writeSpy) and
use the returned array in assertions (e.g., authEvents.some(...) and
authEvents.find(...)); keep helper local to the test file and ensure it returns
typed/nullable-safe results so existing expects (including .reason and .path)
work unchanged.

In `@api/src/auth-logger.ts`:
- Around line 139-148: The extractRequestContext function currently reads only
the x-real-ip header; add a concise JSDoc above extractRequestContext explaining
that this is intentional because x-real-ip is expected to be set by a trusted
reverse proxy and that x-forwarded-for (and similar headers like
cf-connecting-ip or forwarded) are intentionally not used due to spoofing
concerns and because x-forwarded-for is already handled/redacted via
REDACTED_FIELDS—do not change logic, just document the security rationale and
reference the REDACTED_FIELDS policy so future contributors don’t replace
x-real-ip with x-forwarded-for.
- Around line 52-74: The info-level log in configureAuthLogHashKey is too noisy;
replace the console.info call that reports a configured authLogHashKey with a
debug-level or conditional log so it doesn't fire on every startup or test.
Locate configureAuthLogHashKey and change the console.info(`[auth-logger] Auth
log hash key configured...`) to either console.debug or wrap it behind a runtime
check (e.g., only log when NODE_ENV !== 'test' or when a DEBUG/VERBOSE flag is
set) so only operators/devs requesting verbose logs see it; leave the warning
paths and hasWarnedDefaultHashKey behavior unchanged.

In `@api/src/security.ts`:
- Around line 92-94: MIN_AUTH_LOG_HASH_KEY_LENGTH is defined in two places
causing drift; remove the duplicate by exporting the canonical constant from one
module (e.g., export const MIN_AUTH_LOG_HASH_KEY_LENGTH = 16 from security.ts)
and import that single constant where needed in auth-logger.ts. Update
references in resolveAuthLogHashKey and configureAuthLogHashKey to use the
imported constant, remove the local duplicate, and run TypeScript/TSLint to
ensure no leftover shadowed definitions remain.
- Around line 1120-1122: The unguarded call to logAuthEvent in the auth gate
(the middleware that checks sessions) can throw and crash requests; wrap the
logAuthEvent("auth.session.invalid", c.req.raw, {...}) invocation in a try/catch
so any errors from logging/HMAC/IO are swallowed or routed to a non-throwing
fallback (e.g., processLogger.error) and do not propagate, ensuring the
middleware still returns the intended 401/redirect response; apply the same
defensive wrapping pattern to other high-traffic callers of logAuthEvent such as
the handlers referenced in app.ts and authorization.ts.

---

Outside diff comments:
In `@api/src/app.ts`:
- Around line 119-134: The logAuthEvent calls around the authentication check
(after resolveAuthenticatedSessionClaims) can throw and block sending the 401 or
success response; wrap both invocations of logAuthEvent (the failure branch and
the success branch where you pass claims.sub) in try/catch blocks so any logging
error is caught and does not prevent returning the JSON 401 or proceeding with
the 204+cookie refresh; ensure the catch either swallows or records the logging
error safely (e.g., fallback to console.error or a non-throwing logger) so
response flow from resolveAuthenticatedSessionClaims remains unaffected.

- Deduplicate MIN_AUTH_LOG_HASH_KEY_LENGTH (export from auth-logger, import in security)
- Add JSDoc to extractRequestContext explaining x-real-ip choice
- Reduce startup log noise (console.info → console.debug)
- Extract safeLogAuthEvent helper for fault-tolerant logging at all 5 call sites
- Extract extractAuthEvents test helper to deduplicate parse/filter pattern
- Add null guards on .find() results in integration tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 25, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Feb 25, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 25, 2026

Sequence Diagram

Shows how auth-related HTTP requests trigger high-level auth events that are pseudonymized/redacted and emitted as JSON lines to stdout. This captures the primary success path and key denial/invalid-session cases introduced in this PR.

sequenceDiagram
    participant Client
    participant API
    participant Security
    participant AuthLogger
    participant Stdout

    Client->>API: HTTP request (/auth/check, /auth/logout, or API write)
    API->>Security: Validate session / check authorization

    alt /auth/check with valid session
        Security-->>AuthLogger: auth.login.success (subject)
    else /auth/check missing/invalid
        Security-->>AuthLogger: auth.login.failure (reason)
    end

    alt POST /auth/logout with valid session
        Security-->>AuthLogger: auth.logout (subject)
    end

    alt Protected write by non-admin
        Security-->>AuthLogger: auth.denied (subject, reason)
    end

    alt Anonymous request rejected by auth gate
        Security-->>AuthLogger: auth.session.invalid (reason, path)
    end

    AuthLogger->>Stdout: Write redacted, pseudonymized JSON line (timestamp, event, method, path, subject?, ip?)
    Stdout-->>API: Log forwarded to host/syslog/SIEM (out of band)
Loading

Generated by CodeAnt AI

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 25, 2026

CodeAnt AI Incremental review completed.

@ggfevans ggfevans enabled auto-merge (squash) February 25, 2026 09:26
@ggfevans ggfevans disabled auto-merge February 25, 2026 09:26
@ggfevans ggfevans merged commit a63378f into main Feb 25, 2026
10 of 11 checks passed
@ggfevans ggfevans deleted the feat/1104-auth-event-logging branch February 25, 2026 09:26
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
api/src/app.ts (1)

20-20: ⚠️ Potential issue | 🟠 Major

Remove unused safeLogAuthEvent import to satisfy lint.

safeLogAuthEvent is imported but never used, which triggers @typescript-eslint/no-unused-vars and can fail CI.

♻️ Minimal fix
-import { configureAuthLogHashKey, safeLogAuthEvent } from "./auth-logger";
+import { configureAuthLogHashKey } from "./auth-logger";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/app.ts` at line 20, Remove the unused import safeLogAuthEvent from
the import statement that currently reads "import { configureAuthLogHashKey,
safeLogAuthEvent } from \"./auth-logger\""; keep configureAuthHashKey (or
configureAuthLogHashKey) as needed and only import symbols actually used to
resolve the `@typescript-eslint/no-unused-vars` lint error and restore CI; update
the import to only include configureAuthLogHashKey.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/src/auth-logger.ts`:
- Around line 26-27: Replace the fixed DEFAULT_AUTH_LOG_HASH_KEY constant with a
module-scoped lazy fallback: introduce a let fallbackAuthLogHashKey variable and
a getter function (e.g., getAuthLogHashKey()) that returns the configured key
when present and otherwise generates and caches a per-process random key (using
crypto.randomBytes) that meets MIN_AUTH_LOG_HASH_KEY_LENGTH; update places
currently using DEFAULT_AUTH_LOG_HASH_KEY to call getAuthLogHashKey() so the
random fallback is consistent per process and only generated once.

---

Duplicate comments:
In `@api/src/app.ts`:
- Line 20: Remove the unused import safeLogAuthEvent from the import statement
that currently reads "import { configureAuthLogHashKey, safeLogAuthEvent } from
\"./auth-logger\""; keep configureAuthHashKey (or configureAuthLogHashKey) as
needed and only import symbols actually used to resolve the
`@typescript-eslint/no-unused-vars` lint error and restore CI; update the import
to only include configureAuthLogHashKey.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfd9d36 and d0998e3.

📒 Files selected for processing (5)
  • api/src/app.ts
  • api/src/auth-logger.test.ts
  • api/src/auth-logger.ts
  • api/src/authorization.ts
  • api/src/security.ts

Comment on lines +26 to +27
const DEFAULT_AUTH_LOG_HASH_KEY = "rackula:auth-log:v1:default";
export const MIN_AUTH_LOG_HASH_KEY_LENGTH = 16;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace fixed default hash key with per-process random fallback.

When configuration is absent, the current constant fallback generates predictable pseudonyms across instances. A lazily generated per-process random key is safer and matches the intended fallback model.

🔐 Suggested fix
-import { createHmac } from "node:crypto";
+import { createHmac, randomBytes } from "node:crypto";

-const DEFAULT_AUTH_LOG_HASH_KEY = "rackula:auth-log:v1:default";
 export const MIN_AUTH_LOG_HASH_KEY_LENGTH = 16;
+const FALLBACK_AUTH_LOG_HASH_KEY_BYTES = 32;
 type AuthIdentifierType = "subject" | "ip";
 let authLogHashKey: string | undefined;
 let hasWarnedDefaultHashKey = false;
+let fallbackAuthLogHashKey: string | undefined;

 export function resetAuthLogHashConfigForTests(): void {
   authLogHashKey = undefined;
   hasWarnedDefaultHashKey = false;
+  fallbackAuthLogHashKey = undefined;
 }

 function getAuthLogHashKey(): string {
   if (authLogHashKey) {
     return authLogHashKey;
   }
+  if (!fallbackAuthLogHashKey) {
+    fallbackAuthLogHashKey = randomBytes(FALLBACK_AUTH_LOG_HASH_KEY_BYTES).toString("hex");
+  }

   if (!hasWarnedDefaultHashKey) {
     console.warn(
-      "[auth-logger] No auth log hash key configured. Falling back to default auth log hash key; configure RACKULA_AUTH_LOG_HASH_KEY to avoid predictable cross-instance pseudonyms.",
+      "[auth-logger] No auth log hash key configured. Falling back to an ephemeral per-process auth log hash key; configure RACKULA_AUTH_LOG_HASH_KEY for stable pseudonymization across restarts.",
     );
     hasWarnedDefaultHashKey = true;
   }

-  return DEFAULT_AUTH_LOG_HASH_KEY;
+  return fallbackAuthLogHashKey;
 }

Also applies to: 76-89

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/auth-logger.ts` around lines 26 - 27, Replace the fixed
DEFAULT_AUTH_LOG_HASH_KEY constant with a module-scoped lazy fallback: introduce
a let fallbackAuthLogHashKey variable and a getter function (e.g.,
getAuthLogHashKey()) that returns the configured key when present and otherwise
generates and caches a per-process random key (using crypto.randomBytes) that
meets MIN_AUTH_LOG_HASH_KEY_LENGTH; update places currently using
DEFAULT_AUTH_LOG_HASH_KEY to call getAuthLogHashKey() so the random fallback is
consistent per process and only generated once.

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

Labels

size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Basic authentication event logging

1 participant