Skip to content

fix: accounts-passwordless case-insensitive email and audit-argument-checks#14274

Open
dupontbertrand wants to merge 3 commits intometeor:develfrom
dupontbertrand:fix/passwordless-case-insensitive-email
Open

fix: accounts-passwordless case-insensitive email and audit-argument-checks#14274
dupontbertrand wants to merge 3 commits intometeor:develfrom
dupontbertrand:fix/passwordless-case-insensitive-email

Conversation

@dupontbertrand
Copy link
Copy Markdown
Contributor

@dupontbertrand dupontbertrand commented Mar 27, 2026

Summary

Fixes #12412
Fixes #12053

Two related fixes in accounts-passwordless:

Case-insensitive email lookup (#12412)

  • findUserWithOptions: replaced direct { 'emails.address': email } query with Accounts._findUserByQuery, which performs a case-insensitive fallback lookup — matching the behavior already used by requestLoginTokenForUser
  • checkToken: use the stored tokenEmail (from DB) for the SHA256 hash instead of selector.email, and compare emails case-insensitively with .toLowerCase()

The root cause was an asymmetry: requestLoginTokenForUser used _findUserByQuery (case-insensitive) to find the user and generate a token, but the login handler used a direct query (case-sensitive) to verify the token. When a user signed up with [email protected] and later tried to log in with [email protected], the token was generated successfully but the login failed with "User not found [403]".

audit-argument-checks compatibility (#12053)

  • Added check() validation to the requestLoginTokenForUser method arguments, so it no longer throws Did not check() all arguments when the audit-argument-checks package is installed.

Test plan

  • Added unit test for mixed-case email token verification
  • Manual testing with a Blaze repro app:

Summary by CodeRabbit

  • Bug Fixes

    • Passwordless login now handles mixed-case email addresses correctly: token verification is case-insensitive while preserving the original email casing in the authenticated result.
    • Improved reliability of user lookup during passwordless authentication.
  • Tests

    • Added test coverage verifying token validation succeeds with mixed-case email selectors and preserves original email casing.

…#12412)

Use Accounts._findUserByQuery for case-insensitive user lookup during
login, and compare emails case-insensitively when verifying tokens.

Fixes meteor#12412
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for v3-meteor-api-docs canceled.

Name Link
🔨 Latest commit db1e00b
🔍 Latest deploy log https://app.netlify.com/projects/v3-meteor-api-docs/deploys/69c670d9864263000809b952

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for v3-migration-docs canceled.

Name Link
🔨 Latest commit db1e00b
🔍 Latest deploy log https://app.netlify.com/projects/v3-migration-docs/deploys/69c670d991e1c70008aa0498

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Delegates user lookup to Accounts._findUserByQuery, changes requestLoginTokenForUser to validate a single args object with check, makes token email matching case-insensitive, and adds a Tinytest for mixed-case email selector token validation.

Changes

Cohort / File(s) Summary
User lookup & method signature
packages/accounts-passwordless/passwordless_server.js
Replaced manual Meteor.users.findOneAsync composition with Accounts._findUserByQuery(selector, { fields: { services: 1, emails: 1 } }). Changed requestLoginTokenForUser to accept a single args parameter and added check(args, { selector: Accounts._userQueryValidator, userData: Match.Optional(Object), options: Match.Optional(Object) }) before extracting { selector, userData, options = {} }.
Token verification
packages/accounts-passwordless/server_utils.js
Updated checkToken to hash tokenEmail + sequence and compare selector.email vs tokenEmail case-insensitively (both lowercased) while keeping sequence and expiration logic unchanged.
Tests
packages/accounts-passwordless/server_tests.js
Added Tinytest "passwordless - Valid token with mixed-case email (#12412)" verifying token validation succeeds when selector.email is uppercased and that verifiedEmail preserves the stored email casing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: case-insensitive email handling and audit-argument-checks compatibility.
Linked Issues check ✅ Passed All code changes directly address the requirements from both linked issues: case-insensitive email in findUserWithOptions and checkToken [#12412], and check() validation in requestLoginTokenForUser [#12053].
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the two linked issues; no unrelated or extraneous modifications are present.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@dupontbertrand dupontbertrand changed the title fix: make accounts-passwordless email lookup case-insensitive fix: accounts-passwordless case-insensitive email and audit-argument-checks Mar 27, 2026
Copy link
Copy Markdown

@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

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

Inline comments:
In `@packages/accounts-passwordless/passwordless_server.js`:
- Line 109: The function parameter formatting for requestLoginTokenForUser is
lint-breaking; remove the unnecessary parentheses around the single async
parameter. Locate the requestLoginTokenForUser: async (args) => { definition and
change it to use the single-parameter concise form (requestLoginTokenForUser:
async args => {) so Prettier/CI is satisfied.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fe2079ca-f09e-4365-a08a-41a86ece5198

📥 Commits

Reviewing files that changed from the base of the PR and between 43c61d4 and 8b7137c.

📒 Files selected for processing (1)
  • packages/accounts-passwordless/passwordless_server.js

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
packages/accounts-passwordless/passwordless_server.js (1)

110-114: Consider Match.ObjectIncluding to future-proof strict arg validation.

check(args, { ... }) enforces an exact object shape. While the current codebase has no callers passing extra top-level keys, using Match.ObjectIncluding aligns with defensive patterns for core packages—especially given this API already involves a signature change from destructured parameters to a single object.

Suggested improvement
-    check(args, {
+    check(args, Match.ObjectIncluding({
       selector: Accounts._userQueryValidator,
       userData: Match.Optional(Object),
       options: Match.Optional(Object),
-    });
+    }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/accounts-passwordless/passwordless_server.js` around lines 110 -
114, The check call in passwordless_server.js currently enforces an exact args
shape (check(args, { selector: Accounts._userQueryValidator, userData:
Match.Optional(Object), options: Match.Optional(Object) })); update it to use
Match.ObjectIncluding so extra top-level keys are allowed: wrap the existing
shape with Match.ObjectIncluding(...) to accept the current fields while
tolerating future additions; keep the same validators
(Accounts._userQueryValidator, Match.Optional(Object)) and only change the outer
check invocation to Match.ObjectIncluding to future-proof the API.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/accounts-passwordless/passwordless_server.js`:
- Around line 110-114: The check call in passwordless_server.js currently
enforces an exact args shape (check(args, { selector:
Accounts._userQueryValidator, userData: Match.Optional(Object), options:
Match.Optional(Object) })); update it to use Match.ObjectIncluding so extra
top-level keys are allowed: wrap the existing shape with
Match.ObjectIncluding(...) to accept the current fields while tolerating future
additions; keep the same validators (Accounts._userQueryValidator,
Match.Optional(Object)) and only change the outer check invocation to
Match.ObjectIncluding to future-proof the API.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7c3dbd8e-dbc0-461d-8445-befdf209c3e4

📥 Commits

Reviewing files that changed from the base of the PR and between 8b7137c and db1e00b.

📒 Files selected for processing (1)
  • packages/accounts-passwordless/passwordless_server.js

@italojs italojs added this to the Release 3.x.x milestone Mar 27, 2026
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.

accounts-passwordless does not always convert email selector to lowercase requestLoginTokenForUser causes audit-argument-checks to throw error

2 participants