Skip to content

Log email change auth failures to Axiom with structured reason codes - #4268

Open
devkiran wants to merge 2 commits into
mainfrom
log-auth-failures-axiom
Open

Log email change auth failures to Axiom with structured reason codes#4268
devkiran wants to merge 2 commits into
mainfrom
log-auth-failures-axiom

Conversation

@devkiran

@devkiran devkiran commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes
    • Improved authentication failure tracking for email-change requests and confirmations.
    • Invalid, expired, missing, or already-used confirmation links now generate structured failure records.
    • Unauthorized attempts and rate-limit violations are logged with relevant request context.
    • Invalid email-domain requests now consistently record the failure before displaying an error.

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dub Ready Ready Preview Aug 3, 2026 4:22pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds shared authentication-failure logging and applies it to email-change request and confirmation flows. It records classified errors, request metadata, rate-limit details, and authorization failures before rethrowing errors.

Changes

Email-change authentication logging

Layer / File(s) Summary
Authentication failure logging utility
apps/web/lib/auth/log-auth-failure.ts
Adds typed failure reasons, error mapping, structured request metadata logging, asynchronous logger flushing, and callback failure handling.
Email-change request logging
apps/web/lib/auth/request-email-change.ts
Logs rate-limit failures and blocked-domain validation errors with request context before throwing.
Email-change confirmation logging
apps/web/lib/actions/confirm-email-change.ts
Logs invalid, expired, consumed, and unauthorized token failures before throwing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • dubinc/dub#4251: Both changes modify the email-change flow and its token handling.
  • dubinc/dub#4261: This change adds failure logging to the email-change flow introduced there.

Suggested reviewers: steven-tey, pepeladeira

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: structured logging of email-change authentication failures to Axiom.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch log-auth-failures-axiom

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/lib/actions/confirm-email-change.ts`:
- Around line 78-92: Update the error handling around
assertCanConfirmEmailChange and withAuthFailureLogging so only the typed
authorization error emitted by assertCanConfirmEmailChange is logged with reason
"unauthorized"; classify Prisma or other unexpected failures as "unknown" or
send them through the existing error telemetry path. Preserve the existing user
and email context while deriving the reason from the caught error type.

In `@apps/web/lib/auth/request-email-change.ts`:
- Around line 63-65: Update the generic plus-address validation in the request
email-change flow to evaluate newEmail rather than email, while preserving the
existing isEmailDomainBlocked(newEmail) check and rejection condition. Ensure
the requested address is blocked when it is a generic plus-address, without
rejecting valid work addresses based on the current email.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 201f7305-16e7-45f8-b92c-bb9af60cb679

📥 Commits

Reviewing files that changed from the base of the PR and between 8f40bcd and 22ce94f.

📒 Files selected for processing (3)
  • apps/web/lib/actions/confirm-email-change.ts
  • apps/web/lib/auth/log-auth-failure.ts
  • apps/web/lib/auth/request-email-change.ts

Comment on lines +78 to +92
await withAuthFailureLogging(
{
action: "email_change_confirm",
reason: "unauthorized",
userId: user.id,
email: user.email ?? undefined,
},
async () => {
await assertCanConfirmEmailChange({
userId: user.id,
tokenFound,
data,
});
},
);

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not classify every assertion error as unauthorized.

assertCanConfirmEmailChange performs Prisma queries. If either query fails, withAuthFailureLogging records the error as unauthorized because Line 81 forces that reason. Emit a typed authorization error from assertCanConfirmEmailChange, then assign unauthorized only for that error type. Preserve unexpected errors as unknown or route them to error telemetry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/actions/confirm-email-change.ts` around lines 78 - 92, Update
the error handling around assertCanConfirmEmailChange and withAuthFailureLogging
so only the typed authorization error emitted by assertCanConfirmEmailChange is
logged with reason "unauthorized"; classify Prisma or other unexpected failures
as "unknown" or send them through the existing error telemetry path. Preserve
the existing user and email context while deriving the reason from the caught
error type.

Comment on lines 63 to 65
const isGenericEmailWithPlus = email.includes("+") && isGenericEmail(email);
const emailDomainBlocked = await isEmailDomainBlocked(newEmail);
if (isGenericEmailWithPlus || emailDomainBlocked) {

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate newEmail for generic plus-addresses.

isGenericEmailWithPlus checks the current email, but this flow validates the requested newEmail. A generic plus-address can bypass this check when it is the requested address. A user with a generic plus-address can also be blocked from changing to a valid work address.

Proposed fix
-  const isGenericEmailWithPlus = email.includes("+") && isGenericEmail(email);
+  const isGenericEmailWithPlus =
+    newEmail.includes("+") && isGenericEmail(newEmail);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const isGenericEmailWithPlus = email.includes("+") && isGenericEmail(email);
const emailDomainBlocked = await isEmailDomainBlocked(newEmail);
if (isGenericEmailWithPlus || emailDomainBlocked) {
const isGenericEmailWithPlus =
newEmail.includes("+") && isGenericEmail(newEmail);
const emailDomainBlocked = await isEmailDomainBlocked(newEmail);
if (isGenericEmailWithPlus || emailDomainBlocked) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/auth/request-email-change.ts` around lines 63 - 65, Update the
generic plus-address validation in the request email-change flow to evaluate
newEmail rather than email, while preserving the existing
isEmailDomainBlocked(newEmail) check and rejection condition. Ensure the
requested address is blocked when it is a generic plus-address, without
rejecting valid work addresses based on the current email.

Base automatically changed from centralize-auth-rate-limits to main August 3, 2026 19:58
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