# Logging in with Flask

Logging in is extremely similar to signing up! The main (and only) difference is that we don't add the user data to our users dictionary.

All we do is populate the session, since that is what tells us the user is logged in.

This is what we're starting with:

@app.route("/login")
def login():
    return render_template("login.html")

Just as we did with the /signup endpoint, we need to accept POST requests and handle them:

 

 
 


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        pass
    return render_template("login.html")

Then, we need to get the email and password, and see if they match what we have in our users dictionary:




 
 
 
 
 
 


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form.get("email")
        password = request.form.get("password")

        if users.get(email) == password:
            session["email"] = email
            return redirect(url_for("protected"))
    return render_template("login.html")

# Handling incorrect login details

There are two ways to handle incorrect login details:

  1. Send the users to an error page that says "Unauthorized" or something along those lines; or
  2. Be a bit more helpful and send the users back to the login page and show them a message to tell them what went wrong.

DANGER

If the e-mail or password are wrong, it's important you don't say which one is wrong. This is so that a malicious attacker can't keep guessing passwords for an e-mail they know exists.

# Send the user to an error page due to incorrect login details

Super easy, all you do is use abort to raise an exception:










 


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form.get("email")
        password = request.form.get("password")

        if users.get(email) == password:
            session["email"] = email
            return redirect(url_for("protected"))
        abort(401)
    return render_template("login.html")

You can then catch with with @app.errorhandler as we did in How to add error handling to a Flask app.

# Re-render the form and show a message

A slightly better approach would be to use flash() to show an informative message.

This is better because the user then doesn't have to go back to the login page from the error page:










 


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form.get("email")
        password = request.form.get("password")

        if users.get(email) == password:
            session["email"] = email
            return redirect(url_for("protected"))
        flash("Incorrect e-mail or password.")
    return render_template("login.html")

You could take this a step further and pass the email the user typed back to the form so it's already populated when the page refreshes:



 









 

@app.route("/login", methods=["GET", "POST"])
def login():
    email = ""

    if request.method == "POST":
        email = request.form.get("email")
        password = request.form.get("password")

        if users.get(email) == password:
            session["email"] = email
            return redirect(url_for("protected"))
        flash("Incorrect e-mail or password.")
    return render_template("login.html", email=email)

This requires that we change the HTML form slightly also, adding value="{{ email }}". This will put the email there if it's passed. If nothing is passed, then the field will remain empty.





 










{% extends "base.html" %} {% block content %}
<form method="POST">
  <label>
    E-mail
    <input type="email" name="email" value="{{ email }}" />
  </label>
  <label>
    Password
    <input type="password" name="password" />
  </label>
  <input type="submit" value="Log in" />
</form>
<p><a href="{{ url_for('signup') }}">Sign up</a> instead</p>
{% endblock %}

Note that this doesn't tell the user the e-mail they typed is correct, but if it is then it makes it easier for them.