JWT token for password reset

I have an experience (using an assigned C-name domain name) where I have successfully implemented the forgot password feature as described here: https://docs.losant.com/guides/building-an-experience/forgot-password/

I cloned this experience and tried to implement the forgot password feature, and made sure I created a different global JWTsecret, first, but when testing this the token I receive in the email isn’t valid and I see this :image

As a FYI, the cloned experience is using a “{appid}.onlosant.com” domain

Hi Lars,

I am currently looking into this, and will follow up shortly with more information.

Thanks so much!
Julia

Hi @Lars_Andersson,

This messages appears as the result of templating within your Experience Page. To debug this problem I suggest:

  • Experience Render Log - to see the value of the context provided to your page
  • Experience Workflow Debug Log - to see the value of the payload when this page is executed.

Please let me know if you have any additional questions.

Thanks!
Julia

Looks like it fails at the conditional node labelled “Password not reset yet?”
I tried changing the node that creates the token and set it to have no expiration, but it still fails.

I noticed the forgot-password workflow in the experience that works, looks like attached image. This is different from the walkthrough and doesn’t look correct to me.

I just noticed this in the application log, so maybe that is related to my problem. Not sure how the component “successAlert” should be defined though…?
image

Never mind , I found it

<div class="alert alert-success">
  {{.}}
</div>

Fixing the missing successAlert component did not change anything.
If it’s any help, it seems that this problem is only occurs to my account, even if I’m not signed in to the Losant platform as a user and have cleared cache.
What’s so starnge is that it works in the original application just fine, but not in the cloned one.
Now that I know this, it’s not a big problem, but would be curious to find out why this is happening.

I am experiencing the same issue. I followed the new template for ‘Forgot my Password’ located here: https://github.com/Losant/losant-templates/tree/master/library-templates/experiences/forms/forgot-password

Specifically, I get the error: Invalid reset token. Please attempt another password reset request.

Using your hint about it only happening in Cloned Applications led me to the following realization and tests:

  1. In Original Application, worked great, no problems.
  2. In two seperate cloned applications, did not work.
  3. For those two cloned applications, the user it did not work on (my user) had been brought over in the Clone operation.
  4. Invalidating Tokens in the Experience User interface (against my user) did not change the behavior.
  5. Deleting my experience user, and then re-creating it DID fix the error for that user (my user).

Unfortunately my two cloned applications have several users from the original application.
One solution here is to delete them and re-create them each individually.
As I have not built a way for users to change their password, I could go recover the password I created them with and they would be none the wiser, but this seems like there might be an underlying bug that needs to be fixed with validating the JST token against a cloned user?

Edit: Clarification of user / my user. Always referring to my experience user, is me.

I think I have figured it out. I examined the Custom Node in use for the ‘Forgot my Password’ solution. I had to replicate the logic in the workflow so I could follow along with a live payload, however the solution is evidenced if you setup a trigger with the JWT payload, on the custom node editor, I just didnt notice how it was exiting.

A user that is cloned does not have a passwordLastUpdated field.

If your logic checks to make sure the password has not been updated since the token was requested, then it will fail comparing the values.

I suspect I can either force change my users, at time of clone (for future), or insert some function logic to coalesce such that if no date is found, use some arbitrary value that should still work.

Edit: Apologies for hijacking this thread, my issue appears as though it may have had a different cause entirely from the original.

Hey @Kyle_Stokes2,

I’m happy to see that you got your issue solved! But I see that with your edit, that your issue may have been caused by something completely different. Would you be able to tell me more about this?

If there is anything erroneous happening in the platform, I want to be sure that it is addressed.

Thank you,
Heath

Hi Heath,

Slightly erroneous, is that when an Application is cloned, any experience users that get cloned, do not have a passwordLastSet attribute, in the newly cloned application.

This means that the Template Library template, for ‘Forgot My Password’, will not work for those users until they somehow get their password set.

I modified the workflow provided by instead setting mine to check the users lastModified timestamp.

I put an issue up on the github repo with some more information at the link pasted above.

On the same topic, I did have a similar problem with an expired token for password reset.
I cloned part of the “Forgot password” template to invite a new user to an experience.

A user can invite someone as long as they can provide a name and email. the invited person receives an email invitation with a link that takes them to a password reset page.

I couldn’t get it to work and by analyzing the workflow, I figured that the new user password was created after the token creation, even though the “new user” node sits before the “JWT: create” node.
I added a 1 second delay between the two nodes, thinking the creation of a user would need to be completed before the next node is triggered, and it worked:

image

I guess it’s not the best fix, so if anyone has a better idea…

@Jules_Huguenin would you mind exporting and sharing your modified workflow? Make sure not to include any sensitive information within it.

Here is a copy of the workflow:
user-invitation-develop.flow (12.8 KB)
Input template is as follow:

"data": {
   "body": {
      "addUser": "true",
      "newUserEmail": "email@email.com",
      "newUserFirstName": "firstname",
      "newUserLastName": "lastname"
   }
}

Thanks, @Jules_Huguenin. I think this is what is going on …

  • Our “passwordLastUpdated” property is returned in milliseconds
  • JWTs are signed in seconds
  • The comparison of the two times is failing because of rounding issues related to the “passwordLastUpdated” property when comparing the two values to determine if the reset token is still valid

I’m going to file a ticket to tweak the Forgot Password template in light of your use case. Your 1s Delay Node certainly solves the problem, but what I would do instead is add a couple seconds of tolerance to the date comparison in the template’s “Verify Reset Token” custom node.

Thanks for bringing this to our attention.

Brilliant, please let us know when it’s implemented

Hey @Dylan_Schuster
Did you make any progress on this?
Cheers

I actually have not made that update yet, but I’m about to do it right now. FYI me making this change will not update the Forgot Password template you have already imported into any of your applications; if you want to apply my change from the Template Library, you would have to delete all the resources created by this template and then re-import it.

For that reason, it is probably easier for you to apply the one change I’m making manually, which is as follows:

  1. Navigate to the “Verify Reset Token” custom node that was imported as part of the Forgot Password template.
  2. Select the “Password not reset yet?” Conditional Node, which is toward the bottom right.
  3. Change the expression to:
{{formatDate (defaultTo working.user.passwordLastUpdated 0) 'X'}} < {{add working.decoded.iat 10}}

Essentially this changes the condition from “has the user updated their password since the token was issued?” (which comes with the rounding / race condition described previously) to “has the user updated their password since 10 seconds after the token was issued?” That is far more than enough time to account for the issues you were seeing.

Screenshot showing the node with my change is attached.