To add on what cd1zz mentionned, assuming on a web site, With no human intervention on the server side and using a "Use Case" approach:
1) User: Enter more than one pieces of information, for example username and email address, before clicking on "retrieve" password. This prevent account harvesting attacks.
2) System: Verify that both username and password match, generates a long random Id and link it with username in memory. Then, send an email to the user containing the id embedded in a URL (no username!!!). Link only good for a few hours. No need of temporary password here.
3) User receives the email, clicks on the link (HTTPS).
4) System checks the id with the id in memory, retrieve the associated username and displays a web page (always HTTPS) with at least one secret question.
5) User answers the question then click on submit.
6) System displays a screen for the user to enter a new password. User needs to login after to complete the process.
This would obviously be better and more secure if we could add:
- Secure Token
- More secret questions (2 or even 3)
- Even GeoLocation wouldn't be a bad idea (if you try to recover password from a different region than when you last successfully logged in)
- IP banned if attempting recovery to often...
- Account lock out for 10 minutes if more than 3 attempts to answer the secret questions
And I probably forget many little things...
OSCP, GPEN, GWAPT, GSEC, CEH, CISSP