Password Reset
Learn how to implement password reset functionality in your Nuxt application using the Nuxt Users module.
Overview
The module provides a complete password reset flow with:
- Email-based password reset requests
- Secure token-based validation
- Time-limited reset tokens (1 hour expiration)
- Ready-to-use Vue components
- Professional email templates
How It Works
- User requests reset - User enters their email on a forgot password page
- Email sent - A secure reset link is sent to the user's email
- User clicks link - The reset link contains a secure token and email parameters
- Password updated - User sets a new password using the provided form
- Automatic cleanup - Used tokens are automatically deleted
Reset URL Format
Password reset emails include a complete URL with the necessary parameters:
https://yourapp.com/reset-password?token=abc123...&[email protected]
Your reset password page should read these query parameters to populate the reset form.
Reset URL Configuration
The module automatically constructs password reset URLs using your application's base URL and the configured path.
Default Behavior
By default, reset links use /reset-password
as the path:
https://yourapp.com/reset-password?token=abc123...&[email protected]
Custom Reset URL Path
You can customize the path portion of the reset URL:
nuxtUsers: {
passwordResetUrl: '/auth/reset-password', // Custom path
}
This will generate reset links like:
https://yourapp.com/auth/reset-password?token=abc123...&[email protected]
Zero Configuration
The module automatically detects your application's base URL from the incoming request, so you don't need to configure a full base URL. The system intelligently combines:
- Request host: Automatically detected from headers
- Protocol: Detected from
x-forwarded-proto
header or defaults tohttp
- Reset path: Your configured
passwordResetUrl
(default:/reset-password
)
Development vs Production
Development (automatic detection):
- Request to
http://localhost:3000
→ Reset URL:http://localhost:3000/reset-password
Production (automatic detection):
- Request to
https://myapp.com
→ Reset URL:https://myapp.com/reset-password
No manual configuration of base URLs required!
Configuration
Configure the mailer in your nuxt.config.ts
:
export default defineNuxtConfig({
modules: ['nuxt-users'],
nuxtUsers: {
connector: {
name: 'sqlite',
options: {
path: './data/users.sqlite3'
}
},
mailer: {
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'your-app-password',
},
defaults: {
from: '"Your App" <[email protected]>',
},
},
passwordResetUrl: '/reset-password', // URL path for password reset page
}
})
Development Setup with Ethereal Email
For testing during development, you can use Ethereal Email:
nuxtUsers: {
// ... other options
mailer: {
host: 'smtp.ethereal.email',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'your-ethereal-password',
},
defaults: {
from: '"My Nuxt App" <[email protected]>',
},
},
passwordResetUrl: '/reset-password', // Custom URL path (optional)
}
Using the Reset Password Component
NUsersResetPasswordForm
The simplest way to implement password reset is creating a new page called reset-password.vue
and using the NUsersResetPasswordForm
component:
<template>
<div>
<h1>Reset Your Password</h1>
<NUsersResetPasswordForm />
</div>
</template>
This component automatically:
- Reads
token
andemail
from URL query parameters - Provides password and confirmation fields
- Handles form validation
- Makes the API call to reset the password
- Redirects to login page upon success
Custom Implementation
Creating a Forgot Password Form
<template>
<form @submit.prevent="requestReset">
<div>
<label for="email">Email Address</label>
<input
id="email"
v-model="email"
type="email"
required
placeholder="Enter your email"
/>
</div>
<button type="submit" :disabled="loading">
{{ loading ? 'Sending...' : 'Send Reset Link' }}
</button>
<div v-if="message" class="success">{{ message }}</div>
<div v-if="error" class="error">{{ error }}</div>
</form>
</template>
<script setup>
const email = ref('')
const loading = ref(false)
const message = ref('')
const error = ref('')
const requestReset = async () => {
loading.value = true
error.value = ''
message.value = ''
try {
await $fetch('/api/nuxt-users/password/forgot', {
method: 'POST',
body: { email: email.value }
})
message.value = 'Password reset link sent to your email'
email.value = ''
} catch (err) {
error.value = 'Failed to send reset link. Please try again.'
} finally {
loading.value = false
}
}
</script>
Creating a Custom Reset Password Form
<template>
<form @submit.prevent="resetPassword">
<div>
<label for="password">New Password</label>
<input
id="password"
v-model="password"
type="password"
required
minlength="8"
placeholder="Enter new password"
/>
</div>
<div>
<label for="passwordConfirmation">Confirm Password</label>
<input
id="passwordConfirmation"
v-model="passwordConfirmation"
type="password"
required
placeholder="Confirm new password"
/>
</div>
<button type="submit" :disabled="loading">
{{ loading ? 'Resetting...' : 'Reset Password' }}
</button>
<div v-if="error" class="error">{{ error }}</div>
</form>
</template>
<script setup>
const route = useRoute()
const router = useRouter()
const password = ref('')
const passwordConfirmation = ref('')
const loading = ref(false)
const error = ref('')
// Get token and email from URL parameters
const token = route.query.token
const email = route.query.email
const resetPassword = async () => {
if (password.value !== passwordConfirmation.value) {
error.value = 'Passwords do not match'
return
}
loading.value = true
error.value = ''
try {
await $fetch('/api/nuxt-users/password/reset', {
method: 'POST',
body: {
token,
email,
password: password.value,
password_confirmation: passwordConfirmation.value
}
})
// Redirect to login page
await router.push('/login')
} catch (err) {
error.value = 'Password reset failed. The link may be expired or invalid.'
} finally {
loading.value = false
}
}
</script>
API Endpoints
Request Password Reset
Endpoint: POST /api/nuxt-users/password/forgot
Request:
{
"email": "[email protected]"
}
Response:
{
"message": "Password reset link sent to your email"
}
Reset Password
Endpoint: POST /api/nuxt-users/password/reset
Request:
{
"token": "reset-token-from-email",
"email": "[email protected]",
"password": "new-password",
"password_confirmation": "new-password"
}
Response:
{
"message": "Password reset successfully"
}
Security Features
The password reset system includes several security measures:
- Secure tokens: Cryptographically secure random tokens
- Time-limited: Tokens expire after 1 hour
- Single-use: Tokens are deleted after successful use
- No user enumeration: Same response for existing and non-existing emails
- Professional email templates: Clear instructions and security warnings
Email Template
The password reset emails include:
- Clear call-to-action button for easy access
- Fallback URL for copy/paste
- Security warnings about ignoring unwanted emails
- Expiration notice (1 hour by default)
- Both HTML and plain text versions
Troubleshooting
Common Issues
Email not received:
- Check spam/junk folder
- Verify mailer configuration in
nuxt.config.ts
- Ensure email credentials are correct
Token expired:
- Tokens expire after 1 hour by default
- Request a new reset link
Invalid token error:
- Ensure the complete URL from email is used
- Check that token and email parameters are present
- Request a new reset link if the current one is corrupted
Password validation errors:
- Ensure passwords match
- Check minimum password requirements
- Verify password confirmation field
Testing the Flow
- Create a test user account
- Visit your forgot password page
- Enter the test email address
- Check email for the reset link
- Click the link and set a new password
- Verify you can log in with the new password
Next Steps
- Authentication Guide - Learn about the authentication system
- Components Guide - Explore all available Vue components
- Configuration Guide - View all configuration options