Skip to content

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 ​

  1. User requests reset - User enters their email on a forgot password page
  2. Email sent - A secure reset link is sent to the user's email
  3. User clicks link - The reset link contains a secure token and email parameters
  4. Password updated - User sets a new password using the provided form
  5. 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:

ts
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 to http
  • 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:

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:

ts
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:

vue
<template>
  <div>
    <h1>Reset Your Password</h1>
    <NUsersResetPasswordForm />
  </div>
</template>

This component automatically:

  • Reads token and email 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 ​

vue
<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 ​

vue
<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:

json
{
  "email": "[email protected]"
}

Response:

json
{
  "message": "Password reset link sent to your email"
}

Reset Password ​

Endpoint: POST /api/nuxt-users/password/reset

Request:

json
{
  "token": "reset-token-from-email",
  "email": "[email protected]",
  "password": "new-password",
  "password_confirmation": "new-password"
}

Response:

json
{
  "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 ​

  1. Create a test user account
  2. Visit your forgot password page
  3. Enter the test email address
  4. Check email for the reset link
  5. Click the link and set a new password
  6. Verify you can log in with the new password

Next Steps ​

Released under the MIT License.