Flask-Login & Sessions
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Setting Logins
The first function we'll use from flask_login
is called login_user
which handles the part of setting the cookie for the user.
Add this import to your users.py
file (from flask_login import login_user
) and then add login_user(user)
to your register
route.
from flask_login import login_user
...
@user_bp.route('/register', methods=["GET", "POST"])
def register():
form = SignupForm()
if form.validate_on_submit():
user = User.create(form.email.data, form.password.data)
db.session.add(user)
db.session.commit()
login_user(user)
return redirect(url_for("products.index")))
return render_template("users/register.html", form=form)
Once this step is done, anyone who submits this form will be issued a cookie that represents a request from their specific user ID. The cookie is encrypted with a secret value (SECRET_KEY
) in the Flask configuration. We should not arbitrarily set plain text data in cookies for things like authentication data because it's possible for browser or end user to modify this cookie. We wouldn't want to issue a cookie saying this cookie is from User 1, and then have a the end user modify it to look like it comes from User 2. By encrypting the data with our SECRET_KEY
, we can ensure that only our server can encode valid data.
Login
Create a login form in forms.py
from werkzeug.security import check_password_hash
class LoginForm(FlaskForm):
email = StringField('Email', validators=[validators.email(), validators.required()])
password = PasswordField('Password', validators=[validators.required()])
def validate(self):
check_validate = super(LoginForm, self).validate()
if not check_validate:
return False
user = User.query.filter_by(email=self.email.data).first()
if not user or not check_password_hash(user.password, self.password.data):
self.email.errors.append('Invalid email or password')
return False
return True
In our user blueprint (users.py
), add code to handle the login and call login_user
from flask import ..., flash
@user_bp.route('/login', methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).one()
login_user(user)
flash("Logged in successfully.", "success")
return redirect(url_for("products.index"))
This lesson preview is part of the Fullstack Flask: Build a Complete SaaS App with Flask course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack Flask: Build a Complete SaaS App with Flask with a single-time purchase.

[00:00 - 00:25] In the last video, we talked about creating the forms and models to set up user login, but we never got to the point where we're actually logging in a user. That's what we're going to cover in this video. Okay, now that we've created our application, if we hypothetically went through this flow, all we do is create record the database, at no point do we actually set up the user.
[00:26 - 01:27] So in order to do that, what we can do is use flas login to help us set the cookies appropriately. Flas login comes with a form, a function called login user. So that's going to be pretty useful in actually logging in a user. So the way we do that is right here, we would call login user, for example, and then that would log in a user. However, we're going to have to tell flas login how to know that a cookie belongs to a specific user. The way we're going to do that is by defining a user loader. So the user loader takes in a user ID and returns out a user object. So the way we're going to define that is by taking a function that simply returns user.query.get of user ID.
[01:28 - 03:04] So the reason we need to define this is, flas login is going to store the ID automatically, but it doesn't know that we actually have to query the user table to get the record back. So we have to tell flas login exactly how to do that. Now to actually log in, let's go and create a similar form to sign up form that's called the login form. And on the login form, we won't have to have a confirm field, we'll just need to require a password. So here, our form fields look simple, but our validation is going to be a little trickier. So for our validation function, we're going to have to check that the password hash matches. So similar to how in the models.py, we had this generate password hash, or skirk also has this function called check password hash. And so what we can do here is we can say, if the user is not exist, we're going to return an error. So that, you know, there's that append invalid. Now the best practice not to reveal that a user has an account in your login form. So we're also going to check that the password hash matches. So if the password hash of user password is not equal to the password that someone submitted in this form.
[03:05 - 03:48] And the hashes don't match then that means that they have an invalid email or password. And we can return this. Otherwise, we know the form is valid. Okay. So now that we have a login form, we can also implement a login page. Going back in our user's blueprint, we can go ahead and implement slash login. And here, we're going to want to import the login form, which we'll need to import. And if the form is valid, we're going to want to log in the user, not create it.
[03:49 - 04:55] So here, what we can do is query for the user table. And if it exists, then we can log in the user and redirect them. Now there's a few things we can do to improve this. First off is, I think it'd be nice to flash a success message to the user to tell them that they've been logged in successfully. So the way we can do that is, Flask provides us this method called flash, which is something that we can do to show messages to our users. So we can say something like logged in successfully. And we can also add another attribute here that allows us to know what kind of flash it was. Similarly, it would be useful to know if a user was already logged in, and if they're already logged in, what we can do is say, if the user, if we somehow know the current user is logged in, then what we want to do is just redirect them to maybe the products page again.
[04:56 - 05:32] And then if they are logged in, we would want to flash this, but we'd give them a warning and say, you are already logged in. So right now we need a way to know if the current user is logged in. The way we can get the current user is, Flask login will store and track all of that information for us. So we can just use this object called current user, which Flask login will handle the complexity of figuring out which user is currently logged in in this request.
[05:33 - 06:22] So if current user, and we need to know if they're authenticated, because anonymous accounts or non -logged in accounts also get a value here. So the way we can do that is, going back into our models.py file, we're going to go ahead and add a mix in here to user, which will allow us to use Flask logins features here mixed in with the user model. Now, if you're wondering what this user mix in does, the Flask login documentation gives a lot of information, but the short answer is it gives us default implementations for methods that Flask login expects the user class to have. And so it's really important that we define this.
[06:23 - 07:13] So what we can do here is import the user mix in from the Flask login library and add that as a class that our user model inherits from. And the upside of that is it's going to define a lot of these methods here that we're going to need and Flask login is going to look in for. Now that our user mix in is already defined, we're ready to go and we can check that if current user dot is authenticated, which again, was defined from the user mix in, we can say you're already logged in. And if the user's not logged in, current user is going to return something of the kind of anonymous user mix in, which means that the user will not be authenticated.
[07:14 - 07:40] There's one other thing we missed here, which is that we didn't import user and we've used it all over the place in the forms. Well, so to do that, we're just going to import it from our. It's going to create a login form that's similar to registered.py.
[07:41 - 08:14] So here in our login form, we're just going to get email and password. Okay, so now we have login.html. Let's go back into our code and make sure the code for our register form is correct. Then at this point, we should have everything we need .
[08:15 - 08:56] Here we can see a login form and we can see a register form. And now if we check our our application storage, we can actually see that there 's already a session value created for us, which is interesting, but that session value doesn't correspond to a user right now. In fact, if we think about it, there's actually no way in our application to tell if a user is logged in. So what we're going to do is add some stuff into our template. So in the base layout, we might want to add some things into our nav bar to tell if our user is logged in.
[08:57 - 09:47] So I'm going to add some more content to our nav bar here. First off, I'm going to add another section to our nav bar. And then within here, what I can do is I can add maybe a block that says, if the current user is authenticated, flask login by default in jx current user into our ginger context. So we can use jint current user anywhere in our application. We don't have to pass it in to the template. So if the current user is authenticated, maybe we'll just include a text to show their email. And if they're not authenticated, what we can do is we can show a text to show their login link instead. In addition to logging in, we can also show them the register link.
[09:48 - 10:42] All right, let's see what that looks like. Okay, here it shows that we're not currently logged in, and we have the register. One thing we haven't implemented is the ability to show flash messages that we had typed up in our blueprint. But there's no way we render them in the template. So we're going to have to tell flask how to render those flash messages. We can do that by going into the templates. So first off, we're going to go ahead and go into our base layout and figure out where we want our templates to be rendered. I'm thinking right under the nav bar. But it's possible that we're going to be rendering our flashes in different places or if we use a different layout. So what I like to do is actually render that in a macro. So I 'm going to create a macros.hkmail file, where we can create a lot of our future macros going forward.
[10:43 - 11:26] Okay, I'm going to start on a macro called render flashes. And the way this is going to work is we're going to use a flash function called get flash messages. And that will give us the messages that we have set in our blueprint. For example, when we flash this, it will give us that the message is this and the category is warnings. So just do that by using a with statement in ginger. Okay, so I pasted in a bunch of code here, basically get flash messages looks at what flash stores in the flash session. And then it retrieves them and then pops them off the list.
[11:27 - 11:46] Then if there are messages, it's going to loop through each one and render boot strap errors here. And there's going to be a close button. So we can go and try what this looks like by registering for an account and seeing if this shows up. We're going to have to include that macro here. So let's do that.
[11:47 - 12:11] Render flashes is what we called it. And then we're going to have to go ahead import that from here. Okay, so we have imported our macro function and we've set us place for it to show up.
[12:12 - 12:43] Back in our browser, let's go and try registering for something. Let's go and say this is a sample account. And then here, our flashes should have shown up. So let's go and check out what's happening. Maybe we can try and going into the login page and seeing if that worked. All right, so we didn't have a flash when a user registered, but it does show here when I said you are already logged in. And then if we refresh the page, it doesn't show up anymore.
[12:44 - 13:02] Now to go back to our code, we can go ahead and add a flash message when a user signs up. Registered successfully. Great. At this point, we have everything we need. So we can go and try it out.
[13:03 - 13:57] So we already saw an example of how we were able to register account. Let's go ahead and take a look at what's within our application. If we go and inspect the cookies we're storing here, you see that one shows up here for the session and it's this long value. And what this value is, what flash is actually using to look at the details in this session. So flash is encoding some data with our secret key and sending it back to the browser in the form of a token. Every time our browser is issuing a query, it's including this data and flasks is able to decode that and turn it into data. To actually take a look at what flasks is doing, we can actually just go ahead into flask and actually just print the session data. So what we can do is we can import the session here and just on the index, I'm going to go ahead and print the session information.
[13:58 - 14:32] Back in our browser, I'm going to go ahead and reload this page. And then in our terminal, we can go and see what actually happened. So if we ignore all the queries, we 'll see here, this is the data that flasks is actually storing in the session. So user ID is what FlasksLuggen is using to figure out who is currently logged in and there's some other information here as well. Things like your flash messages are also stored here in the session. All right.
[14:33 - 15:05] Now that we've seen that we can log in, register and store data in our session, the next thing we're going to do is implement logout as well as testing. Thank you for watching.