Developers · Users and Permissions
Reset an Authenticated User's Password
Last updated 11 November 2026
This document guides you through adding a password reset functionality to your site. This functionality is complex and is a good demonstration of the different features on Insites.
Prerequisites
To follow the steps in this tutorial, you must understand the required directory structure for your codebase, have a test email set up, and understand the concept of pages, users, Tables, Database Fields, and Permissions. In addition, you must know how to create a form.
- Codebase
- Instance Configuration (test email recipients)
- Pages
- Users
- Database Fields and Tables
- Permissions
- Creating a Sign-Up Form
Steps
Resetting a password is a six-step process:
- Step 1: Create a table to store the password reset request
- Step 2: Create a form to get the user's email
- Step 3: Check the user's email
- Step 4: Store token
- Step 5: Send the email with the password reset instructions
- Step 6: Create the entry point to the workflow
Step 1: Create a Table to Store the Password Reset Request
app/schema/reset_password.yml
name: reset_password
properties:
- name: email
type: stringStep 2: Create a Form to Get the User's Email
Note
If you're using modules, make sure to adjust paths accordingly, for example,
app/forms/recover_password.liquid
---
name: recover_password
resource: reset_password
resource_owner: anyone
redirect_to: /recover-password
flash_notice: You will receive reset password instructions if you provide the right email.
fields:
properties:
email:
validation:
presence: true
email: true
callback_actions: |-
{% graphql g = 'generate_user_temporary_token', email: form.properties.email %}
{% if g.users.results[0] %}
{% graphql res = 'update_password_token', id: g.users.results[0].id, token: g.users.results[0].temporary_token, form_name: 'update_password_token', profile: 'default', property: 'password_token' %}
{% endif %}
---{% form %}
<label for='email'>Email</label>
<input name='{{ form.fields.properties.email.name }}' id='email' type='email'>
<button>Recover password</button>
{% endform %}Step 3: Check the User's Email
Create a GraphQL query to check if the provided email address has a user associated with it in the database. If yes, generate a temporary token to authenticate the request.
app/graphql/generate_user_temporary_token.graphql
query generate_user_temporary_token($email: String) {
users(
per_page: 1
filter: {
email: {
value: $email
}
}
) {
results{
id
temporary_token(expires_in: 24)
}
}
}Step 4: Store the Token
If the user exists, store the value of the generated token in a field (Property) associated with the default profile.
app/user_profile_types/default.yml
name: default
properties:
- name: password_token
type: stringThis way, you can ensure that only the most recent token can be used. To store the actual value, create a GraphQL mutation. The form name, the profile name and the property name are passed in as variables (
app/graphql/update_password_token.graphql
mutation update_password_token(
$id: ID!
$token: String!
$form_name: String!
$profile: String!
$property: String!
) {
user_update(
id: $id
user: {
profiles: [
{
name: $profile,
values: {
properties: [
{ name: $property, value: $token }
]
}
}
]
}
form_name: $form_name
) {
id
}
}Each GraphQL mutation has an associated form configuration; in this case, it's
app/forms/update_password_token.liquid
---
name: update_password_token
resource: User
resource_owner: anyone
fields:
email:
profiles:
default:
properties:
password_token:
validation: { presence: true }
email_notifications:
- send_recover_password
---Step 5: Send the Email with the Password Reset Instructions
After storing the token, email the password reset instructions to the user.app/emails/send_recover_password.liquid
---
name: send_recover_password
to: '{{ form.email }}'
from: 'Example Site <[email protected]>'
reply_to: [email protected]
subject: Reset password instructions
layout: mailer
---Note: The From address must be [email protected], or an address at a domain connected to the instance whose email notifications are live. An email from any other address is refused. See Sending Email from Your Own Domain.
{%- graphql g = 'get_user_with_password_token', email: form.email, profile: 'default' -%}
<h2>Hi {{ g.users.results[0].first_name }}!</h2>
<p>To reset your password, follow the link: <a href='{{ platform_context.host }}/reset-password?token={{ g.users.results[0].default[0].properties.password_token | url_encode }}&email={{ g.users.results[0].email | url_encode }}'>reset password!</a></p>The email relies on a GraphQL query called
app/graphql/get_user_with_password_token.graphql
query get_user_with_password_token($email: String, $id: ID, $profile: String) {
users(
per_page:1
filter: {
email: {
value: $email
}
id: {
value: $id
}
}
) {
results{
id
email
first_name
default: profiles(profile_type: $profile) {
properties
}
}
}
}Step 6: Create the Entry Point to the Workflow
Create a page as an entry point to the workflow.
app/views/pages/recover_password.liquid
---
slug: recover-password
---
<h2>Forgotten Password</h2>
{% if flash.notice != blank %}
<p>{{ flash.notice }}</p>
{% endif %}
{% include_form 'recover_password' %}app/views/pages/reset-password.liquid
---
slug: reset-password
---
{% liquid
graphql g = 'get_user_with_password_token', email: params.email, profile: 'default'
assign token_valid = params.token | is_token_valid: g.users.results[0].id
%}
{% if g.users.results[0].id == blank or token_valid == false or g.users.results[0].default[0].properties.password_token != params.token %}
Unfortunately, provided token is not valid anymore. Please request password instructions again.
{% else %}
<h2>Reset Password</h2>
{% include_form 'reset_password', id: g.users.results[0].id %}
{% endif %}The above page is used to check if the provided token is valid and fetch the user's id based on the email provided in the parameter. Re-use the GraphQL query created earlier.
The page below embeds the form to reset the password.
app/forms/reset_password.liquid
---
name: reset_password
resource: User
resource_owner: anyone
redirect_to: /sign-in
flash_notice: Your password has been updated. You can now log in.
fields:
email:
property_options:
readonly: true
password:
validation:
confirmation: true
password_confirmation:
property_options:
virtual: true
authorization_policies:
- token_is_valid
---{% form %}
<input name='token' value='{{ context.params.token }}' type='hidden'>
<input name='email' value='{{ form.email }}' type='hidden'>
<label for='password'>Password</label>
<input name='{{ form.fields.password.name }}' id='password' type='password'>
<label for='password_confirmation'>Password confirmation</label>
<input name='{{ form.fields.password_confirmation.name }}' id='password_confirmation' type='password'>
{% if form.errors.password_confirmation %}
<p>{{ form.errors.password_confirmation }}</p>
{% endif %}
<button>Reset password</button>
{% endform %}To re-render the previous page, forward the email and token parameters from the email if the password validation fails. The token is also used in an Authorization Policy, where the user is authenticated with this token to ensure they can't change another user's password. You can add more rules to the password field by
Create this Authorization Policy. An Authorization Policy must print true or false on every path, so it has an else branch that prints false:
app/authorization_policies/token_is_valid.liquid
---
name: token_is_valid
---
{% liquid
graphql g = 'get_user_with_password_token', id: params.id, profile: 'default'
assign token_valid = params.token | is_token_valid: g.users.results[0].id
%}
{%- if g.users.results[0].id != blank and token_valid == true and g.users.results[0].default[0].properties.password_token == params.token -%}true{%- else -%}false{%- endif -%}If the user confirms a valid password, the system changes the password and redirects the user to the
Important
Temporary token will be invalidated on user password change.
Next steps
Congratulations! You know how to build a password reset process. Now you can learn about accessing user data: Accessing Authenticated User Data.