2

The below code successfully generates a token and sends a link to the user's inbox for confirmation. But when the user clicks on it, Flask is not recognizing the token it just created. Here is the error message:

"Got exception from ts.loads: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."

The bottom line is that this is what should execute if I could make the confirmation procedure work properly:

return redirect(url_for('tutorials'))

But, as you can piece together by noting the error message that is coming out of @app.errorhandler(404), something is going wrong. I'm really stuck. These tests are being done way before the max_age of 86400 seconds is reached. Any help would be much appreciated!!!

from itsdangerous import URLSafeTimedSerializer

ts = URLSafeTimedSerializer(SECRET_KEY, salt='email-confirm-key')

@app.route('/signup', methods=['GET', 'POST'])
def signup():

#skipping unrelated lines of code

        token = ts.dumps(form.email.data, salt='email-confirm-key')
        subject = 'subject goes here'
        msg = Message(subject=subject, sender='name@email.com', recipients=form.email.data.split())
        link = url_for('confirm_email', token=token, _external=True)
        msg.html = render_template("email_confirmationemail.html", link=link, name=request.form['first_name'])
        with app.app_context():
            mail.send(msg)
        return redirect(url_for('checkyouremail'))


@app.route('/confirmemail/<token>')
def confirm_email(token):
    try:
        email = ts.loads(token, salt='email-confirm-key', max_age=86400)

    #skipping unrelated lines of code

    return redirect(url_for('tutorials'))

@app.errorhandler(404)
def not_found(e):
    print('Got exception from ts.loads: {}'.format(e))
    return render_template('404.html')
okcapp
  • 405
  • 1
  • 4
  • 15
  • Is the token valid? Is the timestamp of the token less than your max_age? – Dor-Ron Aug 08 '17 at 02:02
  • @Dor-Ron Thanks for the note! The person making the failed attempt is going through the whole process all at once and max_age is at 86400 so I should be good there. I did a lot of print statements to explore the token's validity. Not 100% sure what to conclude since I'm new to using this... but I noticed that there is data in the token, and that the user's email is present all the way into the body of the try clause. And, to my surprise, the print statement I put in the except clause never ran. The user's logs just dies off right after the try clause runs (the user gets dumped to my 404 page). – okcapp Aug 08 '17 at 03:15
  • Try catching the exception and logging it, instead of immediately proceeding to the 404 page. – John Gordon Aug 08 '17 at 05:00
  • @John I think you are on to something. So I spent some time reading some documentation and I redeployed several times with different try/except cases... I don't seem to be able to get the code to go into the except clause. Can you be more specific about what I should try? Thanks!!! – okcapp Aug 08 '17 at 07:53
  • `except Exception as e: logging.info('Got exception from ts.loads: %s', e)` – John Gordon Aug 08 '17 at 14:53
  • @John It still wouldn't go into the except clause when I pasted your line of code into my application. So I did a work around which allowed me to get the error message. I rewrote my post to reflect this new information. – okcapp Aug 09 '17 at 02:54

1 Answers1

1

In models.py, my __init__ method for the User class has this line:

self.email = email.lower()

When users create a profile on a phone, their email address often starts with an uppercase letter.

So I just needed to change

token = ts.dumps(form.email.data, salt='email-confirm-key')

to

token = ts.dumps(form.email.data.lower(), salt='email-confirm-key')

so that the email held in the token matched with the email in the database when the user clicked on the confirmation link I sent them. (In short, adding .lower() as shown above in my call do dumps solved my problem).

okcapp
  • 405
  • 1
  • 4
  • 15