Skip to content

Conversation

@coratgerl
Copy link
Contributor

@coratgerl coratgerl commented Dec 6, 2025

Pull Request

Issue

Fixes: #9505

  • Add tests
  • Add changes to documentation (guides, repository pages, code comments)
  • Add security check
  • Add new Parse Error codes to Parse JS SDK

Summary by CodeRabbit

Release Notes

  • New Features
    • Added preventSignupWithUnverifiedEmail option to control signup behavior with unverified emails.
    • Added emailVerifyTokenValidityDuration and emailVerifyTokenReuseIfValid options to configure email verification token lifecycle.
    • Enhanced verifyUserEmails and preventLoginWithUnverifiedEmail options to support conditional logic based on verification context (signup vs. login and authentication method).

✏️ Tip: You can customize this high-level summary in your review settings.

@parse-github-assistant
Copy link

🚀 Thanks for opening this pull request!

@coderabbitai
Copy link

coderabbitai bot commented Dec 6, 2025

📝 Walkthrough

Walkthrough

This PR implements the feature to pass invocation event information to the verifyUserEmails callback, enabling distinction between signup and login scenarios and identification of the auth provider used. The createdWith object containing action ('signup'/'login') and authProvider is now computed and injected into email verification and session creation requests across multiple flows.

Changes

Cohort / File(s) Summary
Test Updates
spec/EmailVerificationToken.spec.js, spec/ValidationAndPasswordsReset.spec.js
Add assertions and expectations for createdWith parameter in verification flows, validating presence of action and authProvider fields in signup and login scenarios.
Option Type Definitions
src/Options/index.js
Introduce new EmailVerificationRequest type; expand verifyUserEmails and preventLoginWithUnverifiedEmail option signatures from boolean to support function callbacks receiving EmailVerificationRequest; add new options preventSignupWithUnverifiedEmail, emailVerifyTokenValidityDuration, and emailVerifyTokenReuseIfValid.
Option Configuration & Documentation
src/Options/Definitions.js, src/Options/docs.js
Remove action field from preventLoginWithUnverifiedEmail option; update help text and documentation to describe createdWith parameter containing signup/login action and auth provider.
Type Definitions
types/Options/index.d.ts
Add VerifyUserEmailsRequest interface; update verifyUserEmails and preventLoginWithUnverifiedEmail signatures to accept function variants returning boolean or Promise.
Core Implementation
src/RestWrite.js
Add public getCreatedWith() method to compute and cache createdWith object based on operation type (create/login) and auth context; integrate into email validation, session creation, and login flows.
Auth Provider Derivation
src/Routers/UsersRouter.js
Extract authProvider from req.body.authData during login to populate createdWith.authProvider, defaulting to 'password' if absent.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • src/RestWrite.js: Review the getCreatedWith() method logic for correctly identifying signup vs. login and auth provider detection; verify caching behavior and integration points across multiple request creation flows.
  • src/Routers/UsersRouter.js: Verify authProvider string derivation handles all auth data scenarios correctly and maintains backward compatibility for password-based authentication.
  • Type signature consistency: Ensure TypeScript definitions in types/Options/index.d.ts align with runtime option expansions in src/Options/index.js and implementation usage in src/RestWrite.js.

Suggested reviewers

  • mtrezza

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature added: event information (createdWith) is now passed to verifyUserEmails invocations.
Description check ✅ Passed The PR description includes the required sections from the template: Issue link, Tasks checklist, and security/license acknowledgments.
Linked Issues check ✅ Passed All coding requirements from issue #9505 are met: createdWith parameter added with action and authProvider fields to verifyUserEmails invocations, supporting conditional verification logic.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #9505 objectives. Updates to preventLoginWithUnverifiedEmail, new preventSignupWithUnverifiedEmail option, and token lifecycle options extend the email verification feature scope appropriately.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@parseplatformorg
Copy link
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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: 0

🧹 Nitpick comments (1)
src/RestWrite.js (1)

774-794: Consider refactoring for improved readability.

The logic for determining action and resolvedAuthProvider is correct but uses nested ternaries that make it harder to follow. Consider refactoring to use explicit conditionals for better maintainability:

-  const action = authProvider ? 'login' : isCreateOperation ? 'signup' : undefined;
-  if (!action) {
-    return;
-  }
-  const resolvedAuthProvider = authProvider || (action === 'signup' ? 'password' : undefined);
+  let action;
+  let resolvedAuthProvider;
+  
+  if (authProvider) {
+    action = 'login';
+    resolvedAuthProvider = authProvider;
+  } else if (isCreateOperation) {
+    action = 'signup';
+    resolvedAuthProvider = 'password';
+  } else {
+    return;
+  }
+  
   this.storage.createdWith = { action, authProvider: resolvedAuthProvider };
   return this.storage.createdWith;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e78e58d and cfe22b3.

📒 Files selected for processing (8)
  • spec/EmailVerificationToken.spec.js (4 hunks)
  • spec/ValidationAndPasswordsReset.spec.js (1 hunks)
  • src/Options/Definitions.js (1 hunks)
  • src/Options/docs.js (1 hunks)
  • src/Options/index.js (2 hunks)
  • src/RestWrite.js (4 hunks)
  • src/Routers/UsersRouter.js (1 hunks)
  • types/Options/index.d.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2025-11-08T13:46:04.940Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: For new Parse Server options, verify that the option is documented in src/Options/index.js and that npm run definitions has been executed to reflect changes in src/Options/docs.js and src/Options/Definitions.js. README.md documentation is a bonus but not required for new options.

Applied to files:

  • src/Options/docs.js
  • types/Options/index.d.ts
  • src/Options/index.js
  • src/Options/Definitions.js
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: Tests in the parse-server repository should use promise-based approaches rather than callback patterns with `done()`. Use a pattern where a Promise is created that resolves when the event occurs, then await that promise.

Applied to files:

  • spec/EmailVerificationToken.spec.js
📚 Learning: 2025-10-16T19:27:05.311Z
Learnt from: Moumouls
Repo: parse-community/parse-server PR: 9883
File: spec/CloudCodeLogger.spec.js:410-412
Timestamp: 2025-10-16T19:27:05.311Z
Learning: In spec/CloudCodeLogger.spec.js, the test "should log cloud function triggers using the silent log level" (around lines 383-420) is known to be flaky and requires the extra `await new Promise(resolve => setTimeout(resolve, 100))` timeout after awaiting `afterSavePromise` for reliability, even though it may appear redundant.

Applied to files:

  • spec/EmailVerificationToken.spec.js
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`. The preferred pattern is to create a Promise that resolves when an expected event occurs, then await that Promise.

Applied to files:

  • spec/EmailVerificationToken.spec.js
📚 Learning: 2025-05-04T20:41:05.147Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1312-1338
Timestamp: 2025-05-04T20:41:05.147Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`.

Applied to files:

  • spec/EmailVerificationToken.spec.js
📚 Learning: 2025-12-02T06:55:53.808Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-12-02T06:55:53.808Z
Learning: When reviewing Parse Server PRs that add or modify Parse Server options, always verify that changes are properly reflected in three files: src/Options/index.js (where changes originate), src/Options/Definitions.js, and src/Options/docs.js. The correct workflow is: make changes in index.js first, then run `npm run definitions` to automatically replicate the changes to Definitions.js and docs.js.

Applied to files:

  • types/Options/index.d.ts
  • src/Options/index.js
  • src/Options/Definitions.js
📚 Learning: 2025-11-08T13:46:04.940Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

Applied to files:

  • src/Options/index.js
📚 Learning: 2025-11-17T15:02:48.786Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.

Applied to files:

  • src/Options/index.js
🧬 Code graph analysis (3)
spec/EmailVerificationToken.spec.js (1)
src/RestWrite.js (6)
  • verifyUserEmails (992-992)
  • user (330-330)
  • user (926-926)
  • user (1543-1543)
  • user (1824-1824)
  • res (623-627)
src/RestWrite.js (1)
src/Auth.js (1)
  • authProvider (552-552)
src/Routers/UsersRouter.js (1)
src/RestWrite.js (3)
  • authProvider (781-786)
  • request (845-852)
  • request (981-988)
🪛 Biome (2.1.2)
src/Options/index.js

[error] 45-57: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 189-189: Expected a statement but instead found '?'.

Expected a statement here.

(parse)


[error] 193-193: Expected a statement but instead found '?'.

Expected a statement here.

(parse)


[error] 201-201: Expected a statement but instead found '?'.

Expected a statement here.

(parse)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: Node 20
  • GitHub Check: MongoDB 8, ReplicaSet
  • GitHub Check: MongoDB 6, ReplicaSet
  • GitHub Check: Node 18
  • GitHub Check: Node 22
  • GitHub Check: Redis Cache
  • GitHub Check: MongoDB 7, ReplicaSet
  • GitHub Check: PostgreSQL 16, PostGIS 3.5
  • GitHub Check: PostgreSQL 17, PostGIS 3.5
  • GitHub Check: PostgreSQL 18, PostGIS 3.6
  • GitHub Check: PostgreSQL 15, PostGIS 3.5
  • GitHub Check: PostgreSQL 15, PostGIS 3.3
  • GitHub Check: PostgreSQL 15, PostGIS 3.4
  • GitHub Check: Docker Build
  • GitHub Check: Code Analysis (javascript)
  • GitHub Check: Benchmarks
🔇 Additional comments (15)
src/Options/docs.js (1)

112-112: Documentation update looks good.

The updated description clearly explains the new createdWith parameter that indicates whether the invocation is for signup or login and the authentication provider used. This aligns well with the PR objective and the implementation in other files.

Based on learnings, ensure this change was generated by running npm run definitions after updating src/Options/index.js.

spec/ValidationAndPasswordsReset.spec.js (1)

287-287: Test expectation correctly validates the new createdWith parameter.

The test verifies that during login verification flow, createdWith contains the expected action: 'login' and authProvider: 'password' values. This provides coverage for the primary password-based login scenario.

src/Routers/UsersRouter.js (1)

143-157: Implementation correctly derives auth provider for verification context.

The logic properly:

  1. Extracts auth provider(s) from req.body.authData keys, joining multiple providers with comma if present
  2. Defaults to 'password' when no authData is provided
  3. Creates the createdWith object with action: 'login' for the verification callback

This is consistent with the pattern used in RestWrite.js (see lines 780-785) and enables the verification function to make conditional decisions based on the authentication method.

src/Options/Definitions.js (1)

636-641: Generated definitions correctly reflect the new createdWith parameter documentation.

Based on learnings, ensure this file was generated by running npm run definitions after making changes to src/Options/index.js, rather than being manually edited.

types/Options/index.d.ts (2)

29-40: Well-structured interface for the verification request.

The VerifyUserEmailsRequest interface properly models:

  • Standard request fields (master, ip, installationId)
  • The new createdWith object with typed action union ('login' | 'signup') and authProvider string
  • Optional fields are correctly marked (e.g., createdWith is optional for scenarios like resend requests)

This provides good TypeScript support for developers implementing conditional verification logic.


89-90: Option types correctly updated to support function-based configuration.

The type changes properly allow both:

  • Simple boolean values for static configuration
  • Functions receiving VerifyUserEmailsRequest and returning boolean | Promise<boolean> for conditional logic

This enables the use case described in the linked issue #9505 (conditional verification based on auth provider).

src/RestWrite.js (2)

837-856: LGTM!

The integration of getCreatedWith() in the email validation flow correctly provides the invocation context for email verification callbacks.


1003-1030: Verify scenarios where getCreatedWith() returns undefined.

The fallback logic at lines 1014-1018 reconstructs the createdWith object when getCreatedWith() returns undefined. This defensive pattern is appropriate if legitimate scenarios exist where getCreatedWith() cannot provide a value at this point in the execution flow. Confirm whether:

  1. Passing tests exercise code paths where this fallback is used
  2. There are documented scenarios where getCreatedWith() returns undefined in the session token creation flow

If no such scenarios exist and tests pass, the fallback may be unnecessary legacy code worth removing.

spec/EmailVerificationToken.spec.js (5)

301-309: LGTM!

Test correctly verifies that the createdWith field is now included in the verification request and has the expected value for signup scenarios.


370-378: LGTM!

Test assertions correctly updated to include the new createdWith field in the request keys and verify its value.


413-443: LGTM!

The new test effectively verifies that createdWith is provided during signup when email verification blocks session creation. The test:

  • Correctly configures the server with verification requirements
  • Verifies the spy is called the expected number of times
  • Asserts the correct createdWith value with signup action and password auth provider

445-476: LGTM!

The new test properly verifies that createdWith includes the correct auth provider during login verification. The test flow is logical:

  1. Creates a user first
  2. Reconfigures server with verification callback
  3. Attempts login and verifies the createdWith parameter has login action

867-901: LGTM!

Correctly asserts that createdWith is undefined for verificationEmailRequest (resend) scenarios, which makes sense since resending doesn't represent a new signup or login action.

src/Options/index.js (2)

46-57: LGTM!

The new EmailVerificationRequest type properly documents the request structure passed to email verification callbacks, including the new createdWith field that provides context about the invocation (signup vs login) and auth provider used.


189-203: LGTM!

The updated signatures for verifyUserEmails and preventLoginWithUnverifiedEmail correctly extend these options to accept functions that receive an EmailVerificationRequest and return a boolean or Promise. This enables conditional verification logic based on the createdWith context, which was the goal of this PR.

The documentation clearly explains the new functionality and indicates that the function receives a request object with createdWith information.

Note: The static analysis errors about TypeScript-only syntax are expected for Flow files and can be ignored.

@codecov
Copy link

codecov bot commented Dec 6, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.57%. Comparing base (e78e58d) to head (cfe22b3).

Additional details and impacted files
@@           Coverage Diff           @@
##            alpha    #9963   +/-   ##
=======================================
  Coverage   92.56%   92.57%           
=======================================
  Files         191      191           
  Lines       15544    15557   +13     
  Branches      177      177           
=======================================
+ Hits        14389    14402   +13     
  Misses       1143     1143           
  Partials       12       12           

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

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.

Add invocation event information to verifyUserEmails parameters

2 participants