You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express项目密码重置Token GET请求异常排查求助

Troubleshooting Password Reset Token Not Passing in Express App

Hey there, let's work through this password reset token issue step by step. Based on the details you shared, here are key areas to check and fix:

1. Verify Route Mounting & GET Route Implementation

First, confirm your users route is mounted correctly in app.js. If you're using:

app.use('/users', require('./routes/users'));

Then your users.js GET route path /reset-password/:token maps to the full URL /users/reset-password/:token—which matches your email link, so that's good.

Now make sure your GET route properly captures the token, validates it, and passes it to the new-password.hbs template:

// In routes/users.js
router.get('/reset-password/:token', async (req, res) => {
  try {
    // Log the token to confirm it's being received
    console.log("Received reset token:", req.params.token);

    // Check if token exists in DB and hasn't expired
    const user = await User.findOne({
      resetToken: req.params.token,
      resetTokenExpiry: { $gt: Date.now() } // Ensure token is not expired
    });

    if (!user) {
      return res.redirect('/users/login'); // Or show an error page for invalid/expired token
    }

    // Pass the token to the template so it can be used in the form
    res.render('new-password', { token: req.params.token });
  } catch (err) {
    console.error("Error handling reset token:", err);
    res.redirect('/users/login');
  }
});

The critical part here is passing token: req.params.token to the render function—without this, your template won't have access to the token.

2. Check new-password.hbs Template Integration

Your template needs to include the token either in the form action or as a hidden input to ensure it's passed back in the POST request. Here's a working example:

<!-- views/new-password.hbs -->
<form action="/users/reset-password/{{token}}" method="POST">
  <!-- Optional: Add hidden input to explicitly pass the token -->
  <input type="hidden" name="token" value="{{token}}">
  
  <div>
    <label for="newPassword">New Password</label>
    <input type="password" id="newPassword" name="newPassword" required>
  </div>
  <div>
    <label for="confirmPassword">Confirm Password</label>
    <input type="password" id="confirmPassword" name="confirmPassword" required>
  </div>
  
  <button type="submit">Update Password</button>
</form>

If the template doesn't reference {{token}}, the token won't be available to the form, breaking the flow.

Double-check that the token stored in your user database matches the one in the email link. Add a log when generating the token to confirm consistency:

// In your password reset request handler (where you send the email)
const resetToken = crypto.randomBytes(32).toString('hex'); // Example token generation
console.log("Generated reset token:", resetToken);

// Save token to user document
user.resetToken = resetToken;
user.resetTokenExpiry = Date.now() + 3600000; // 1 hour expiry
await user.save();

// Generate link (your updated code)
const resetUrl = `http://${req.headers.host}/users/reset-password/${resetToken}`;
console.log("Reset link sent:", resetUrl);

Manually copy the logged resetUrl and paste it into your browser—if the req.params.token in the GET route matches the logged token, the issue isn't with the link itself.

4. Rule Out Middleware Interference

Ensure no authentication middleware (like isAuthenticated) is accidentally applied to the reset password route. This route should be publicly accessible, so it shouldn't require a logged-in user. For example, if you have middleware applied to all /users routes, exclude the reset path:

// In app.js or users.js
router.use((req, res, next) => {
  if (req.path.includes('/reset-password')) {
    return next(); // Skip auth for reset routes
  }
  isAuthenticated(req, res, next);
});

5. Check Token Expiry Logic

If your token is expiring too quickly or the expiry check is broken, the GET route will redirect before rendering the password form. Confirm your resetTokenExpiry field is set correctly (e.g., Date.now() + 3600000 for 1 hour) and the query in the GET route uses $gt: Date.now() to check for unexpired tokens.

内容的提问来源于stack exchange,提问作者user8331511

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:58:36