-
Notifications
You must be signed in to change notification settings - Fork 1k
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
feat: Change to using resetToken hash in DB #8041
Conversation
Thanks for working on this @jaiakt! I don't fully know the dbAuth code, so maybe I'm missing something obvious here, but how does the unhashed token get to the client? Correct me if I'm wrong, but shouldn't the flow be like this?
|
Ah yeah I think that basically is the flow except for step 3. The backend application has to define a handler in which it typically sends an email to the user containing the token (in a password reset link). We don't send the token back to the client. |
Thanks 🙂 But still, that password reset link needs the unhashed token, right? With the code in this PR the handler gets the user object (if I understand the code correctly), and the user object only has the hashed token |
Ohhh yes you're completely right! Let me think about this a little more |
@Tobbe I don't love this solution but we can update the user's resetToken to have the raw token before calling the handler. I can update the docs to explain this behavior if it's not too hacky. |
I like it! 🙂 This also makes this fully backwards compatible, right? Except for tokens already stored in the DB I guess |
Yup should be backwards compatible! Yeah tokens stored in the db probably won't be but they should expire and should be easily replaceable by using the forgot password flow again. Ty for the catch 😄 |
@jaiakt Can you take a look at the failing test case please? |
@Tobbe just learned how to run tests locally lol. Fixed! |
I shouldn't have assumed you knew how to. Sorry |
No worries! Ty for pointing out the broken test. All the CI checks are still a bit confusing to me |
I noticed you tagged this as a breaking feature. Is this considered breaking because it should be backwards compatible? |
Yeah, and unfortunately they're pretty flaky at the moment 🙁 So we might have to rerun them a few time to make them all pass
I made an edit to your PR description trying to describe why I marked it breaking. It's not really breaking, I just wanted to make sure we added some extra info to the release notes for whatever version of RW this PR is released in |
f53bafd
to
4366e41
Compare
This looks good to me, just want to get @cannikin's eyes on this too before merging |
Sorry for the wait! This look great, thanks again! |
Addresses #6855.
This PR makes it so we don't store raw
resetToken
s in our database but instead, the sha256 hash of the token. This makes it so if a database is compromised, an attacker can't stealresetToken
s and reset users' passwords.One catch with this PR is that the user defined
handler()
takes in aUser
object which it relies on for fetching theresetToken
to generate a password reset link. Because now theUser
object will instead contain aresetToken
hash, we need to make the raw token also available. I solve this by mutating theUser
object before calling the handler and explain this in the documentation forforgotPassword.handler()
. This is potentially breaking if the application refetches theUser
object in the handler but not sure why they'd do that 🤔Edit by Tobbe:
I've marked this as feature-breaking, but it's not really breaking. Just wanted to make sure that we highlight that any in-transit password resets will break when users upgrade RW to whatever version this is released in.
For low- to medium-traffic sites it's probably not a problem. Maybe just have an error message that asks users to try again if the token doesn't match.
For high-traffic sites, and/or for the best end-user experience, what developers can do is temporarily disable pw resets. Query their db and wait until no more valid reset tokens exist (by looking at
resetTokenExpiresAt
) and then upgrade and finally re-enable pw resets