loading...
Cover image for Build Email Verification from Scratch With Masonite Framework and JSON Web Tokens

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

nioperas06 profile image Junior Gantin Updated on ・3 min read

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

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 

Setup database

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

$ pipenv install PyMySQL

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

Add ‘active’ attribute to User Model

Let’s create a new migration:

$ craft migration add_active_to_users_table --table=users

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')

Apply your migrations 😄

$ craft migrate

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

Then

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

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

$ pipenv install masonite-notifications

Let’s create a notification for email verification.

$ craft notification EmailVerificationNotification

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)

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’)

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')

Define fillable attribute ‘activate’ on User Model

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

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')

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()

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!

Posted on by:

nioperas06 profile

Junior Gantin

@nioperas06

Software Developer Living In Cotonou, Benin.

Discussion

markdown guide
 

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.

 

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.