DEV Community

Cover image for Build Email Verification from Scratch With Masonite Framework and JSON Web Tokens
Junior Gantin
Junior Gantin

Posted on • Edited on

Build Email Verification from Scratch With Masonite Framework and JSON Web Tokens

Masonite Framework is a modern and developer centric Python web framework. The architecture of Masonite is much more similar to the Laravel framework.

In this tutorial, I’ll show you how to build email verification from scratch for your Masonite application.

Masonite comes with a CLI tool called Craft. Craft provides an easy way to scaffold what you need for authentication using a simple command:

$ craft auth
Enter fullscreen mode Exit fullscreen mode

The above command generates everything you need for authentication: 4 new controllers, 5 new templates and 6 new routes. So you want to handle a user email verification and validate the email. There we go!

Create new Masonite project and scaffold authentication

$ pipenv install masonite-cli
$ craft new masonite-app-with-user-verification 
$ cd masonite-app-with-user-verification 
$ craft install 
$ craft auth 
Enter fullscreen mode Exit fullscreen mode

Setup database

In order to register users, we will need a database. Let’s use a MySQL Database.

$ pipenv install PyMySQL
Enter fullscreen mode Exit fullscreen mode

Create new database and put your database credentials into .env file:

DB_DRIVER=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=masonite
DB_USERNAME=root
DB_PASSWORD=root
Enter fullscreen mode Exit fullscreen mode

Add ‘active’ attribute to User Model

Let’s create a new migration:

$ craft migration add_active_to_users_table --table=users
Enter fullscreen mode Exit fullscreen mode

Then, add new active attribute:

from orator.migrations import Migration
class AddActiveToUsersTable(Migration):
    def up(self):
         with self.schema.table('users') as table:
             table.boolean('active').default(False)

    def down(self):
         with self.schema.table('users') as table:
             table.drop_column('active')
Enter fullscreen mode Exit fullscreen mode

Apply your migrations 😄

$ craft migrate
Enter fullscreen mode Exit fullscreen mode

Why use JWT for email verification?

JSON Web Tokens are a good way of securely transmitting information between parties.

For email verification, we need to send a random hash to registered user.

Generate new jwt token on registration

We need to use JSON Web Token implementation in Python:

$ pipenv install PyJWT
Enter fullscreen mode Exit fullscreen mode

Then

data = {'email': user.email}
encoded = jwt.encode(data, os.environ.get('KEY'), algorithm='HS256')
token = str(encoded, 'utf-8')
Enter fullscreen mode Exit fullscreen mode

Now, we need to send a mail. Masonite provides a package call notification that can help us perform this.

$ pipenv install masonite-notifications
Enter fullscreen mode Exit fullscreen mode

Let’s create a notification for email verification.

$ craft notification EmailVerificationNotification
Enter fullscreen mode Exit fullscreen mode

Our notification should send an e-mail with a link containing the verification token.

from notifications import Notifiable

class EmailVerificationNotification(Notifiable):
def mail(self):
    return self.subject('New account signup!') \
        .driver('smtp') \
        .heading('Masonite App With User Verification') \
        .line('In order to use your account, you have to validate your email address.') \
        .line('Please click on the link below.') \
        .action('Validate my account', href=self._link)
Enter fullscreen mode Exit fullscreen mode

Not bad.

Then, let’s send that email to our users:

if token:
    Notify.mail(EmailVerificationNotification, to=user.email, link='http://localhost:8000/activate/{0}'.format(token))
    Session.flash(‘success’, ‘Almost done! Please check your email to complete the registration process.’)
    return Request.redirect(‘/login’)
Enter fullscreen mode Exit fullscreen mode

If your smtp credentials are correct, you’ll have this in your mail:

Email verification

Create a route for email verification

get('/activate/@token', 'RegisterController@validate')
Enter fullscreen mode Exit fullscreen mode

Define fillable attribute ‘activate’ on User Model

class User(Model):
    __fillable__ = ['name', 'email', 'password', 'active']
Enter fullscreen mode Exit fullscreen mode

Validate users

def validate(self, Request):
    if Request.param('token'):
        data = jwt.decode(Request.param('token'), os.environ.get('KEY'), algorithms=[‘HS256’])
        user = User.where('email', data['email']).first()
        if user:
            user.active = True
            user.save()
            Session.flash('success', 'You\'re in! Let\'s login!')
    return Request.redirect('/login')
Enter fullscreen mode Exit fullscreen mode

Last thing! Login users:

def store(self, Request, Session):
    user = User.where('email', Request.input('email')).first()
    if user.active:
        if Auth(Request).login(Request.input('email'), Request.input('password')):
            return Request.redirect('/home')
        return Request.redirect('/login')
    else:
        Session.flash('warning', 'Please check your email to complete the registration process.')
        return Request.back()
Enter fullscreen mode Exit fullscreen mode

Your user is now verified 🔥

I’ll release this stuff inside a Masonite package. If you want to contribute to the development of the package or interested in the development of Masonite then be sure to join the Slack channel or star the repo on GitHub.

Feel free to add you comments for further discussion. The entire code for this tutorial is available on Github. Thanks!

Top comments (2)

Collapse
 
darksmile92 profile image
Robin Kretzschmar

Nice one! Really good explaination thanks for writing it down.
I think this helps to understand the steps behind a verification even if one does not use Masonite.

Collapse
 
whereo profile image
whereo

Don't use a single key for authentication and especially not your application-key. That should be secret at any time (hashed or not).
Just generate a random key for the user and salt it with the users email address or the timestamp. Needs an additional entry in your User model of course.