From f5b25e782d50a45af4eef748201e2c6942d66343 Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:10:00 +0100 Subject: [PATCH 1/3] feat: add documentation for password reset --- _includes/cloudcode/cloud-code.md | 47 +++++++++++++++++++++++++++++++ _includes/rest/users.md | 2 ++ 2 files changed, 49 insertions(+) diff --git a/_includes/cloudcode/cloud-code.md b/_includes/cloudcode/cloud-code.md index 29436d21..6633796d 100644 --- a/_includes/cloudcode/cloud-code.md +++ b/_includes/cloudcode/cloud-code.md @@ -761,6 +761,53 @@ Parse.Cloud.afterLogout(async request => { - if a user logs out and no `_Session` object was found to delete - if a `_Session` object is deleted without the user logging out by calling the logout method of an SDK +## beforePasswordResetRequest + +*Available only on parse-server cloud code starting 8.5.0* + +Sometimes you may want to run custom validation on a password reset request before the reset email (or any other channels in the future) is sent. The `beforePasswordResetRequest` trigger can be used for blocking password reset requests (for example, if the user is banned), implementing rate limiting, or adding additional validation logic. + +This function provides control in validating a password reset request before the reset email is sent. It is triggered after the user is found by email, but before the reset token is generated and the email is sent. + +```javascript +Parse.Cloud.beforePasswordResetRequest(request => { + if (request.object.get('banned')) { + throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User is banned.'); + } +}); +``` + +You can also add rate limiting to prevent abuse of the password reset endpoint: + +```javascript +Parse.Cloud.beforePasswordResetRequest(request => { + // Your validation logic here + if (request.object.get('banned')) { + throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User is banned.'); + } +}, { + rateLimit: { + requestLimit: 5, + windowMs: 60000 // 1 minute + } +}); +``` + +### Considerations +- It waits for any promises to resolve +- The user object is available on `request.object` - this is the user found by email +- If the function throws an error, the password reset email will not be sent +- You can use `Parse.Error.EMAIL_NOT_FOUND` to prevent information disclosure about whether an email exists in the system + +#### The trigger will run... +- When a password reset is requested via `/requestPasswordReset` endpoint +- After the user is found by email address +- Before the reset token is generated and email is sent + +#### The trigger won't run... +- If the email address doesn't match any user in the system +- If the request is invalid + # LiveQuery Triggers ## beforeConnect diff --git a/_includes/rest/users.md b/_includes/rest/users.md index 2cffd23b..f34dea20 100644 --- a/_includes/rest/users.md +++ b/_includes/rest/users.md @@ -186,6 +186,8 @@ print(result) If successful, the response body is an empty JSON object. +You can use the [`beforePasswordResetRequest`]({{ site.baseUrl }}/cloudcode/guide/#beforepasswordresetrequest) Cloud Code trigger to add custom validation logic before the password reset email is sent. + ## Retrieving Users You can also retrieve the contents of a user object by sending a GET request to the URL returned in the location header when it was created. For example, to retrieve the user created above: From 250bb9032716cbd196d9f222bdb92c12cbf5a17a Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:36:21 +0100 Subject: [PATCH 2/3] Update cloud-code.md --- _includes/cloudcode/cloud-code.md | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/_includes/cloudcode/cloud-code.md b/_includes/cloudcode/cloud-code.md index 6633796d..b91e37fd 100644 --- a/_includes/cloudcode/cloud-code.md +++ b/_includes/cloudcode/cloud-code.md @@ -763,11 +763,11 @@ Parse.Cloud.afterLogout(async request => { ## beforePasswordResetRequest -*Available only on parse-server cloud code starting 8.5.0* +*Available only in Cloud Code on Parse Server >= 8.5.0.* -Sometimes you may want to run custom validation on a password reset request before the reset email (or any other channels in the future) is sent. The `beforePasswordResetRequest` trigger can be used for blocking password reset requests (for example, if the user is banned), implementing rate limiting, or adding additional validation logic. +The `beforePasswordResetRequest` trigger is invoked before a password reset email is sent. It is triggered after the user is found by email, but before the reset token is generated and the email is sent. It can be used for blocking password reset requests, implementing rate limiting, or adding additional validation logic. -This function provides control in validating a password reset request before the reset email is sent. It is triggered after the user is found by email, but before the reset token is generated and the email is sent. +An example would be to prevent sending a password reset email if the user has a ban flag set in your application. ```javascript Parse.Cloud.beforePasswordResetRequest(request => { @@ -780,7 +780,7 @@ Parse.Cloud.beforePasswordResetRequest(request => { You can also add rate limiting to prevent abuse of the password reset endpoint: ```javascript -Parse.Cloud.beforePasswordResetRequest(request => { +Parse.Cloud.beforePasswordResetRequest(async request => { // Your validation logic here if (request.object.get('banned')) { throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User is banned.'); @@ -788,25 +788,25 @@ Parse.Cloud.beforePasswordResetRequest(request => { }, { rateLimit: { requestLimit: 5, - windowMs: 60000 // 1 minute + windowMs: 60_000 } }); ``` -### Considerations -- It waits for any promises to resolve -- The user object is available on `request.object` - this is the user found by email -- If the function throws an error, the password reset email will not be sent -- You can use `Parse.Error.EMAIL_NOT_FOUND` to prevent information disclosure about whether an email exists in the system +Considerations: -#### The trigger will run... -- When a password reset is requested via `/requestPasswordReset` endpoint -- After the user is found by email address -- Before the reset token is generated and email is sent +- The user object is available on `request.object`, which is the user who requested the password reset. +- If the function throws an error, the password reset email will not be sent. -#### The trigger won't run... -- If the email address doesn't match any user in the system -- If the request is invalid +The trigger will run: + +- When a password reset is requested via `/requestPasswordReset` endpoint. +- After the user is found by email address. +- Before the reset token is generated and the email is sent. + +The trigger won't run: + +- If the email address doesn't match any user in the system. # LiveQuery Triggers From 8559c1524ed2c517c0ee64f5908d0b71fd806d02 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:36:37 +0100 Subject: [PATCH 3/3] Update cloud-code.md --- _includes/cloudcode/cloud-code.md | 1 - 1 file changed, 1 deletion(-) diff --git a/_includes/cloudcode/cloud-code.md b/_includes/cloudcode/cloud-code.md index b91e37fd..b104ba4e 100644 --- a/_includes/cloudcode/cloud-code.md +++ b/_includes/cloudcode/cloud-code.md @@ -781,7 +781,6 @@ You can also add rate limiting to prevent abuse of the password reset endpoint: ```javascript Parse.Cloud.beforePasswordResetRequest(async request => { - // Your validation logic here if (request.object.get('banned')) { throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User is banned.'); }