-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add password reset initiated via web form #7210
Comments
Thanks for suggesting. There are some parts I want to get clarified, it may just be the wording, but to make sure we approach this the right way:
A link in an email cannot practically invoke a POST request. I say practically because, while it is technically possible to add JS or a form to a HTML email, it will likely be blocked by every major email provider and email client. In addition, such an email has a higher SPAM score and is likely to harm your email domain reputation. In addition, consider users whose email client may fall back to plain-text.
The desired flow indicates a likely flaw in your approach, where you describe a user clicking on a link in an email just to receive yet another email with a link to click on. This seems like a XY problem where you go from an approach to looking for possible implementations, instead of going from a problem to looking for possible approaches. I suggest to zoom out and try to describe the scenic context in which you want a user to reset their password. |
I am actually using the My initial attempt with the button/link clicked in an email actually needs to either I want to do this as much as possible without requiring client side JavaScript to make thinks simple. |
I agree that the flow is rather complex, but it is based on what Parse Server provides right now. It would be kind of nice and simpler when But that would require generating fresh How would you handle this? |
Thanks for providing more details. I assume this is the flow you would prefer: Case a):
Then there is another use case, that could be considered: Case b):
The second use case may not seem to apply to yours at first sight, but it faces the same issue, that a password reset form requires a pre-generated token. The difference between both cases is:
Possible approaches:
|
My case is always case a) as I only use Parse Server via iOS and Android apps with their client side SDK. Initiating password reset from an app via client side SDK is easy, but requires the Which is not ideal and generates support requests where people can not find X, do not know what Y is, etc... I can improve this in the app, that is correct. But for now - sending an email with a simple link and clear flow sounds like a better approach to me. In other words, I do not plan to develop a fully fledged client side web app handling account related things with Parse Server, yet even using Parse Server in a mobile app still at the moment provides certain valid email based use cases, like email validation, and password reset performed by showing an ownership of the email address. I also think this is absolutely fine, since many apps and websites use these types of flow, so they are very familiar to most people nowadays. |
Can you please provide a complete step-by-step (1,2,3...) example of the flow you are referring to and you want to achieve with Parse Server? |
Neither variant a, nor variant b are at the moment possible to do easily without JavaScript talking client side via XHR to the REST API. I am currently trying to implement variant b which may sound like more steps but is simpler to implement. Variant a requires less steps but Does my explanation make any sense? The email verification flow, as well as password reset flow in parse server currently does not contain any HTML based way to start the process. Verification email is sent automatically after signup performed via REST API, and password reset email is sent automatically after performing POST to REST API endpoint Then the flow continues via series of 302 redirects and GET/POST requests going to Recently, an endpoint was added to POST
I am proposing the same, to initiate password reset with a similar form as here, but using the
|
Step 3a):
Step 3b):
Generally, we want to follow best practice that provides a flow that is familiar for users. I looked into Instagram as an example and found:
That would conclude we should go with the current concept of pre-generating a token. Maybe a disadvantage we have here is that we do not use a TTL index to delete unused tokens, so they stay in the DB unless invalidated. Now, to address the use case you described, I suggest to create a password reset token in the after @mman Would that address your use case? |
Thanks @mtrezza for the detailed proposal. We are on the same page here. My initial idea, and PR implementation goes with 3b) and POST. It does work, it does not break RFC 2616, uses the same method like The instagram like solution where password reset token is generated in I see only one drawback there:
The proper solution to this problem should probably be to just extend password reset validity period in case where a valid password reset token exists for a user. And this will require some more changes. Minus of the instagram like solution will be that there is no simple endpoint to initiate password reset from the web. That will still require manual coding outside of parse-server. What do you think? I will investigate instagram like solution during today, but I'm still in favor of including the step 3b) solution as outlined in the PR #7207. |
How did you conclude that? Another other issue with 3b) is that it basically circumvents the security mechanism of the password reset token and makes it useless, because it will only be generated as a by-product. If we allow an endpoint as suggested in 3b), we are short circuiting the token mechanism, which would be the same as removing the feature.
Tokens can be reused as long as they are valid. |
I meant that to point out that I went with POST instead of GET because POST that triggers password reset flow is not idempotent. Much like
Oh cool, thanks for the link. I did not catch this PR, let me take a look and draft something along this alternative solution. |
@mtrezza Just to clarify, adding a method to My opinion is that better fit would be adding a method to the Is my understanding correct? |
To summarize, I think we can conclude the following:
It needs to be implemented in both, or how would you access a new method in the user controller? |
The
|
Well, the |
UserController is definitely internal. I agree. However when you expose this method via I agree that use of AppCache may be internal, and for a concrete example, the email sending was replaced via
what do you think? |
Yes, the endpoint should require the master key.
Since this is user specific, it may be more intuitive and concise to implement a
Maybe it would better be called Also, it may have to be called with option |
I may be missing something (not familiar with JS SDK, only Android and iOS), but how would As for |
It would be implemented much like the This way, this could even be called client side, if someone decides to do that; we already have some methods that require the master key to discourage invoking them client side (such as push notifications), but in a special set-up, a developer may want to call this client side. The process to implement this would be:
If you look at |
Honestly, although I try to understand why you may prefer to attach the method to the
Adding new method to generated direct password reset link there means:
That means 4 PRs, across 4 repositories, spending time of at least 4 reviewers/core contributors. All I need is to include a simple "change your password now" HTML link in an email generated via I am all for simplicity and consistency, and I do not want to pollute any public APIs with anything more that necessary. The Cloud Code API is currently neat and clean and simple. And no, it is not only used to to declare and start Cloud Code functions and jobs. It is used to specify beforeSave and afterSave hooks, to specify live query event related methods. To send email using configured adapter, to react to afterLogin. The cloud code API has been and is evolving over time as needs arise. From the architectural and security point of view, I do not believe I want the The whole point of secure password reset flow nowadays is that:
Why would I want to skip 2 and get the token directly on the client? What purpose would it serve? I'd agree that we can attach the method to the |
Maybe you want to read the class description of
I think I understand now where your objection comes from, but this is incorrect. The Parse JS SDK is also an integral part of Parse Server, not solely a client SDK. You are comparing the Parse JS SDK to other client SDKs, which leads to wrong assumptions about whether the method belongs there. The SDK is also used for methods are only considered "internal" by the fact that they require the master key. Therefore it makes sense to add the method to
I am actually not sure that was a fully correct implementation, but I approved of that PR because we do not have a
It takes 2 PRs as I already wrote earlier. As long as the time is invested in a sustainable solution, there will be reviewers available. If someone down the road wishes to implement this for other client SDKs, they are free to do that. But again, this is not about making this method available client side via master key, that's just a side effect, it is about making it available internally in Parse Server via Look, one of the benefits of a PR compared to your custom solution is that we evaluate this in a broad context. I had to dismiss your earlier suggestions because of security implications, RFC violation and out-of-scope use of Maybe you are overestimating the effort because of 2 PRs, or do you need any help with how to go about this? |
Thanks @mtrezza, I will take a look. I have put into production our previously discussed Since the code does not align with the way you'd like to see it implemented I am keeping it for now in my fork and will try to get it incorporated via I have yet to investigate how to best prepare the custom route to trigger the password reset, but from my quick look at #7230 it seems to be a matter of rendering a web form and forwarding a POST to Also, I have migrated from thanks, |
That would be nice.
|
New Feature / Enhancement Checklist
Current Limitation
When a user needs to change his/her password, a POST request has to be performed to the REST endpoint
/parse/requestPasswordReset
with appropriately filled HTTP headers, namelyX-Parse-Application-Id
andX-Parse-REST-API-Key
.This is typically handled via JS, iOS, or Android client side SDK, and can not be triggered via plain HTML email or HTML webpage by simply using a form, without resorting to JavaScript XHR.
Example Use Case
Feature / Enhancement Description
I would like to offer my users a feature where they can change their password by clicking a link directly from HTML email, by simply HTTP POST-ing their
username
(email address) to some API endpoint to avoid use of client side JavaScript.After they click the link, they should be redirected to a page informing them that the instructions to reset the password were sent to their email address.
Looking at the current state of https://github.com/parse-community/parse-server/blob/master/src/Routers/PublicAPIRouter.js I propose to modify POST to
/request_password_reset
to start the password reset flow when onlyusername
is present.This is in line with how the
/resend_verification_email
endpoint works.The functionality will then be as follows:
POST /request_password_reset
that requiresusername
. Parse Server generates password resettoken
in a db, sends password reset email withusername
, andtoken
, and redirects topassword_reset_initiated.html
.GET /request_password_reset
with requiresusername
, andtoken
, and redirects tochoose_new_password.html
choose_new_password.html
form prompts for new password, and submits to:POST /request_password_reset
withusername
,token
, andnew_password
.password_changed.html
, or toinvalid_link.html
when token already expired.Example implementation is provided here: #7207
Alternatives / Workarounds
The only alternative I am aware of is to use client side JavaScript and XHR to trigger the password reset flow by posting to
/parse/requestPasswordReset
endpoint, handling the response, and changing the HTML DOM appropriately to indicate that instructions were sent to email address.The text was updated successfully, but these errors were encountered: