Extending the Authentication System
The video reviews core authentication components and introduces additional features such as email verification and password reset. These extensions improve security and completeness but were intentionally left as optional challenges.
Token-Based Email Verification
Email verification relies on cryptographically secure, unpredictable tokens that are hashed before storage. Tokens should include expiration timestamps and can be delivered as short alphanumeric codes or links, with HTTPS enforced for security.
Password Reset Flow
Password reset requires generating a short-lived token, sending a recovery email, and validating the token upon use. The system must not reveal whether an email exists and should invalidate prior tokens and optionally active sessions after a password change.
Session Management Considerations
Invalidating sessions after password changes requires centralized session storage (e.g., database or cache systems). While common in large applications, it may not be necessary for simpler systems.
Email Delivery and Best Practices
Transactional emails must prioritize high deliverability and include both HTML and plain-text versions. Security warnings, retry mechanisms, and reputable email services are essential to prevent spam filtering and failed deliveries.
Database Design for Tokens
Token management should include expiration timestamps, user associations, and hashing. Systems may separate token types into different tables or use a unified structure with type distinctions, depending on design preference.
Security Pitfalls and Mitigations
Common risks include predictable tokens, information leakage, brute-force attacks, and poor rate limiting. Systems should implement rate limiting, avoid exposing account existence, and regularly clean up expired tokens.
Key Takeaways
Raw tokens should never be stored, expiration is mandatory, and user enumeration must be prevented. Email verification and password reset are security mechanisms, not just convenience features.
We've just been through a lot of things. We have dealt with creating users, hashing passwords, logging in, creating cookies, middleware, CSF protection. There is a lot of layers to authentication and authorization. I hope you have seen that it's not as difficult as some people make it out to be. I have intentionally left out some pieces, as I mentioned in the previous
previous episode we have email verification, password reset. We would also need something like token generation and sending emails if we were to build a fully fledged authentication system that we don't really need for our admin right now. But I think it's a really interesting challenge for you to tackle yourself and you to take on after you've been through this entire course and add this to your blog so you can
You can try and work with these things yourself because you have all of the tools, you have all of the resources, you just need to sit down and try and do it. But to give you a small guide, I just want to run through the different parts. So whenever we have a sign up form, we want to validate that the user, who they say they are, or at least that they own the email that they will be using to interact with the application.
And for that, we will need tokens. We can do tokens in many different ways. You can have code like five, six different digits. You can have a long token that you click and you enter a page for a link. There may be different ways of doing this. The two main use cases
in this authentication space is to verify email ownership and resetting passwords. We want to have a token that is cryptographically random and unpredictable. We would also like to hash the tokens before we store them in the database for the same reasons as we hash our passwords. It's similar to password handling, but we don't really need it to be as robust. So this is tokens.
You will have, again, a model and a table and store it and hash it. You will use a different hashing algorithm, right? But much of it stays the same. For email verification, we would like a user to confirm that they own the email address that they have provided to us. This prevents spam account and also prevents typos during registration. It also requires an element to be able to recover a lost password.
Some places is also a compliance or regulation issue that you need to adhere to. The process is quite simply that we create a user, we then create a secure token, then we store both the user's password, hash it, we store the token, and we hash it, and then we need an expiration date on this token. And this can typically be like 24 hours if it's for like validating an email.
We will then send an email with either a link or six or seven digits that the user needs to enter into our form on the page. Which one you choose, both is fine, but links from our email domain or domain that hasn't had a lot of positive interaction, let's call it that, can sometimes end in spam if they have a link in them.
I would suggest that you use a five or six alphanumeric digit token and send that to the user. And then once they have created the account, they will be redirected to a page where they put redirected to a page where they put in this code. And that is how we validate that they own the email. It's really important that we have our exploration. We've already been through this.
In most cases, 25 hours, but it can also be longer or shorter, but try and stick around 25 hours, maybe 48 hours. We always should use HTTPS to make sure that they don't get intercepted in between requests. Next, we have password reset implementation.
And this is really helpful when users forget their passwords right. So whenever they can remember the password, they give us the email, we send them email to this email right with a recovery link that they can click and then reset. We want to never reveal an email if an email exists in the system. We always want to return the same response, whether or not the email exists.
And we want to use a shorter token exploration compared to the verification token, so maybe an hour, half an hour, 10 minutes, depending on the use case. We will also invalidate any existing tokens before creating a new one for a specific user. So the flow is the user sends us their request password reset with their email, with sentiment email, with a token and a link.
where they will then land on one of the pages that we own. We validate that the token that they come from, which is added to the URL, is the one that we created, and it's coming from us, and it belongs to the user. Then we will, if possible, invented all sessions after the password has been changed, and then we can also send an email about the password change. Whether or not we can
and validate the session depends on our setup. We cannot do it in our current setup. You will need to store it in something like Redis, or maybe even in the database before we can invalidate all sessions. You will typically see this in large app. So on Twitter or Facebook, you can see your sessions from different devices, and you can go and invalidate them. So it requires more of a setup, but for most use cases, it's also not really necessary.
could technically also add captures, which is these little forms that you have to fill out to ensure that this is a real user and not a robot filling out this form. We can lock the events to an audit trail so we can see who and from where are people requesting a new password. Finally, we also need to talk about the email service.
There's a big difference between transactional emails and marketing emails. Transactional emails are something that is triggered by a user, like the reset password request, whereas the marketing ones are where we want to promote the stuff we are selling. We want to make sure that these transactional emails get delivered. So it's really important that we follow requirements for high deliverability,
We use best practices, so you should always include an HTML and text version so that no matter what email client provider the user have, they can receive the email, which has some clear call to actions. It's also important to add security warnings that, hey, if you did not request this, let us know or ignore it. Finally, we also need to look a little bit on the database design considerations
We want to have a different table for different types of tokens. You could technically have everything in one table. It requires a little bit of a code setup. So it's also like a preference of what you want. So we can technically have a type, and then we handle the logic in the code. But also, it is reasonable to have different tables for different types of tokens. So we have very clear separation of concern, always include
exploration timestamps, a link to the user or the account. We are a foreign key that is associated with token. You can also consider something like, should we soft delete or hard delete something? So we can always reference back to all the trails. But this again, we're getting into stuff that is more complex and more advanced and most system doesn't really need these elements. Right. That was a very quick one down off.
of what you can do to extend this authentication system we have just built. If you look at some common pitfalls, one is token predictability, using sequential IDs at times times, we don't really have this issue because we use UIDs. Be careful of not leaking any information that should not be leaked. For example, if you have different responses from existing and non-existing emails, that's really, really bad.
We also wanna make sure we have rate limiting in place so we don't have these brute force attacks and we deny, we watch out for spam and deny service attacks. We also, we need to worry about poor email deliverability. We don't want our emails to go to spam, especially if users are trying to reset their passwords for application.
We need to have retry mechanisms so we don't just fail to send something and then never do anything. So it's important that we use a good email service or reputable email service to send these emails. Right. Look at the
material in the episode notes for this, walk through this episode a few times or listen through it a few times. But the key takeaways that you should be aware of is we never store raw tokens. We always have them. We always have expirivation. We always wait limits. We don't reveal anything about existing users in the system. We have email application and password reset as security features, not only as a convenience for the user. Consider adding audit and lock
operations so we know what's going on, make sure you clean up expired tokens regularly, and then also test your email deliverability before you are going to production. Right, that's our indication. In the next episode, we're going to be looking at modern hypermedia and how we can take this app that has used a very traditional approach to building web UIs and make it feel more modern and more
according to what users are normally familiar with so we don't, for example, load an entire page. So we can make little interactivity in the elements of the page. So that's going to be the focus of the next module.