Password Reset Functionality: Part 1

In Part 1 of Password Reset Functionality we will cover the following:

  • Creating the request new password page
  • User email validation
  • Generating and sending the unique password reset link to user’s email

The Form

First, let’s start with the request new password page. This is actually a pretty simple page containing a form with a single field and a submit button. You already know how to create a form and add elements inside it, so we won’t show this in details.

Form method is set to post:

The input is a simple text field:

And the button is a submit button:

We will use the field, to check user’s email, and if a valid email address and if it exists into our database, we will use it to send the password reset link to it. Let’s add the client-side validation first. Select the email field, and add new validation rule:

From the text category select the E-mail validation rule:

Then add new rule:

And select Required:

We are done with the client-side validation.

The Server Action

Save your page and open the Server Connect Panel:

Create new server action:

We create it in the Passwords folder and call it request_new:

Click Globals and click the browse icon, next to the Linked Page field:

Browse to your page, and select it (the password request page we just created).
Then select your form from the Form menu:

And click the Import from form button:

Right click steps:

Add database connection:

Select your connection if you already defined one, or setup a new one:

Right click the database connection step:

And from the Validator category add Validate Data:

Click the validate options button:

Add new validation rule:

Double click the expression field and click the dynamic data picker:

Choose your form input, under $_POST as a value:

In the linked field enter the form input name, this way the validation message will be displayed under the input and the validation styles will be applied to it:

Then add a validation rule:

From the Databse category add Exists in Database rule. It checks if the field exists in the database and displays an error if does not exist:

Select your database connection, the table containing your users details and the column you want to check. In our case this is the email column. Customize the error message per your needs:

Click the save button:

We are done with the validation. If the validation fails, the rest of the steps below it won’t run.
Right click the validation step:

Add Database query:

And click the query builder button, to setup the query:

Select and add your users table:

We will need the password and email fields only, so add them:

Then open the Conditions tab:

We will filter the table by the email column, so select it from the dropdown and click the dynamic data picker button to select a filter value:

This should be the email form input, which validated in the previous step:

Click OK:

IMPORTANT! TURN OFF THE OUTPUT OPTION FOR THE DATABASE QUERY STEP!
This is required as you don’t want your user details exposed in the browser console:

Then right click the query step:

From the Core Actions add Repeat:

Click the dynamic data picker to select a value for the repeat:

This should be your database query:

IMPORTANT! TURN OFF THE OUTPUT OPTION FOR THE REPEAT STEP!

Then right click steps inside the repeat and from the Core Actions, add Set Value:

Add same name in both Name and Global Name fields. This is what we are going to use later in the password reset link. We call this step hash:

Select a dynamic value for it:

We will create a hashed value using users email and the current password as a salt. Select the email, under repeat and click the formatter button:

Right click email, open the cryptographic menu and select Generate SHA1 Hash:

Select Salt and click the dynamic data picker button to select a value:

Select the password under repeat, and click the select button:

Click Select:

And click Select to apply the dynamic value for the Set Value step:

The step generating the unique hash for the dynamic reset link is ready. We will also need the email, so right click the hash set value step:

And add another Set Value step:

We enter email in the name and global name fields:

Then click the dynamic data picker to select a value for it. The value should be the email returned by the repeat:

Now as we have our setvalue steps ready let’s setup mail options.
Right click the Repeat step:

Add Setup Mailer:

Setup your send mail options (SMTP or default server mailer) and right click the Setup Mailer step, when you are done:

Add Send Mail:

Select your mailer and enter your mail subject:

Then setup the sender name and email:

Click the dynamic data picker button, for the recipient email:

This is the email entered in the form input, so select it:

Change the Format to HTML:

And click the edit content button:

Enter some text. For example Click here to reset your password. Then highlight some part of the text to convert to a link:

Click the link button from the editor toolbar:

Enter the link to the page, that will be used for entering the new password, and add ?email={{email}}&id={{hash}} after it.
We are going to use the email URL parameter to filter the users by the email and the id URL parameter to validate the user. So {{email}} and {{hash}}` here are the global names of the Set Value steps we created earlier. They will be replaced by the email and unique hash in the link:

Example link: https://yoursite.com/password_reset.html?email={{email}}&id={{hash}}

Click Save when you are done:

Save your server action and close the server connect panel:

Back on the page, select the form and click the Make Server Connect Form button:

Then select your server action:

Select the server action which we just created and click the select button:

And you are done, just save your page. The email with the dynamic reset page link will be generated and send to any user, which email exists in the database. For invalid emails you will see an error message:

Of course you can add a form reset action on success, or redirect to any other page if you like.

In Part 2 we will show you how to create the password reset page and the server action which will update the password in the database.

8 Likes

very detailed and useful HowTo

and to protect against X-Site Request Forgery, when Server Side API integration comes alive in Wappler, we can protect against XSRF with simple server-side calls to eg

public function xsrf_create($decrypted_string, $key)
{

//create XSRF encrypted token
}

public function xsrf_validate($encrypted_string, $decrypted_string, $key)
{
//...validate encrypted token with sent values
}

:wink:

1 Like

Hi @Teodor , is there an easy way to set an expiry on the generated hash? So a user may only have 1 hour to click the email link before it expires and they have to generate a new request?

1 Like

just add a date time field, set it to NOW when sending the hash and check that field in you query when the hash is submitted from the email link

2 Likes

Did you ever figured out how to do this. Setting a time limit for token to expire?

Yes I followed Brian’s advice and used a date time field to log when the hash was generated. Then if it isn’t used within 1 hour it won’t be accepted

1 Like

Thanks!

I am stuck on this step as I can’t click any of the buttons in the Validate Options window? Even created the page from scratch to make sure.

I think a bug was introduced in the latest update, reported here. Hopefully it will be fixed in the next update.

1 Like

What logic/condition would you use to check again that date time field. I am struggling to set a condition in the MySQL query to check if the DATETIME is more than say 1 hour in the past.

You can use the time difference function (timediff() from memory, not at computer) which is available via the picker

I can’t find it in the pick in the DB Query builder? when I am setting a condition?

Select NOW and then the formatter to get the time diff options.

But I can’t compare it to the field where it has the time where they requested the reset link.

I’m not exactly sure what you are trying to do but if I understand correctly you are trying to check off the current time is within an hour of the timeframe?

In your query:

Your field is greater than NOW date add-1 hour using the formatter.

I’m not on my computer right now or ID supply you with a screenshot.

Thanks @brad and @Hyperbytes. I worked it out. I think I was getting confused with the pickers.
Also the time {NOW} in Wappler comes up as UTC and not server, but in mysql NOW() is local server time. So it also added to the confusion.

Yes, I think i recall a post some time ago about the NOW issue, something to do with how kinex deals with dates. You can use NOW.toLocaltime()

1 Like

Thanks @Hyperbytes I will try that. It can get very confusing very quickly with different values of NOW.
:blush::+1:

@Hyperbytes, is there a way to set NOW.toLocaltime() as a Global setting, so you can select it like you would select NOW etc from the picker on the server side?
So I don’t have to keep setting it for each Server action that needs it?
Also for me NOW.toLocaltime() still sets UTC even though the server systems time is set to proper local time.
No reallyt sure where to set it to local time.

NOW returns your server time, not the user time, nor your local time.
If you want to use a specific timezone use NOW_UTC to get the time in UTC time and add hours to it.