diff --git a/codeflix/codeflix/forms.py b/codeflix/codeflix/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..23f260f5c40ff5672c52f280fd91ef04442838a8
--- /dev/null
+++ b/codeflix/codeflix/forms.py
@@ -0,0 +1,11 @@
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth.models import User
+
+
+class SignUpForm(UserCreationForm):
+    """
+    Extends the django generic UserCreationForm to get all the fields.
+    """
+    class Meta:
+        model = User
+        fields = ['first_name', 'last_name', 'username', 'email']
diff --git a/codeflix/codeflix/migrations/0001_initial.py b/codeflix/codeflix/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..9cf868900704b5eef6003cdb1114fea430419c33
--- /dev/null
+++ b/codeflix/codeflix/migrations/0001_initial.py
@@ -0,0 +1,25 @@
+# Generated by Django 3.0.2 on 2020-02-13 22:35
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Profile',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('email_confirmed', models.BooleanField(default=False)),
+                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]
diff --git a/codeflix/codeflix/migrations/__init__.py b/codeflix/codeflix/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/codeflix/codeflix/models.py b/codeflix/codeflix/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..62cd63b14a282cc2c21c4907bfeedf0fa469379e
--- /dev/null
+++ b/codeflix/codeflix/models.py
@@ -0,0 +1,21 @@
+from django.contrib.auth.models import User
+from django.db import models
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+
+# Create your models here.
+
+
+class Profile(models.Model):
+    """
+    The Profile of a user. Adds new fields.
+    """
+    user = models.OneToOneField(User, on_delete=models.CASCADE)
+    email_confirmed = models.BooleanField(default=False)
+
+
+@receiver(post_save, sender=User)
+def update_user_profile(sender, instance, created, **kwargs):
+    if created:
+        Profile.objects.create(user=instance)
+    instance.profile.save()
diff --git a/codeflix/codeflix/settings.py b/codeflix/codeflix/settings.py
index 4b7ffd3e30428530a3abdd00106c92312d257f34..d1bea51b74538d68a4a34bec71cf7ab169cc1b58 100644
--- a/codeflix/codeflix/settings.py
+++ b/codeflix/codeflix/settings.py
@@ -39,6 +39,7 @@ INSTALLED_APPS = [
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
+    'codeflix',
     'codeforces',
 
     # For the frontend
diff --git a/codeflix/codeflix/tokens.py b/codeflix/codeflix/tokens.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f2e22baab807687bb68d3229a2529d6cb8b862b
--- /dev/null
+++ b/codeflix/codeflix/tokens.py
@@ -0,0 +1,26 @@
+from django.contrib.auth.tokens import PasswordResetTokenGenerator
+
+
+class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
+    """
+    Create a unique token generator to confirm email addresses.
+    """
+    def _make_hash_value(self, user, timestamp):
+        """
+        Hash the user's primary key and some user state that's sure to change
+        after an account validation to produce a token that invalidated when
+        it's used:
+        1. The user.profile.email_confirmed field will change upon an account
+        validation.
+        2. The last_login field will usually be updated very shortly after
+           an account validation.
+        Failing those things, settings.PASSWORD_RESET_TIMEOUT_DAYS eventually
+        invalidates the token.
+        """
+        # Truncate microseconds so that tokens are consistent even if the
+        # database doesn't support microseconds.
+        login_timestamp = '' if user.last_login is None else user.last_login.replace(microsecond=0, tzinfo=None)
+        return str(user.pk) + str(user.profile.email_confirmed) + str(login_timestamp) + str(timestamp)
+
+
+account_activation_token = AccountActivationTokenGenerator()
diff --git a/codeflix/codeflix/urls.py b/codeflix/codeflix/urls.py
index 19366cb1f71112b8df76e46ef45714f6f6d79747..e0156a75eef1b281a357d17e42b04bbe2a6a9354 100644
--- a/codeflix/codeflix/urls.py
+++ b/codeflix/codeflix/urls.py
@@ -17,9 +17,14 @@ from django.contrib import admin
 from django.contrib.auth import views as auth_views
 from django.urls import include, path
 
+from . import views
 
 urlpatterns = [
     path('', auth_views.LoginView.as_view(template_name='index.html'), name='index'),
     path('accounts/', include('django.contrib.auth.urls')),
+    path('accounts/signup/', views.UserCreateView.as_view(), name="signup"),
+    path('accounts/activate/sent', views.UserActivationEmailSentView.as_view(), name='account_activation_sent'),
+    path('accounts/activate/<uidb64>/<token>', views.UserActivateView.as_view(), name='account_activation'),
+    path('accounts/activate/done', views.UserActivateDoneView.as_view(), name='account_activation_done'),
     path('admin/', admin.site.urls),
 ]
diff --git a/codeflix/codeflix/views.py b/codeflix/codeflix/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..d35f9a952959db9e11da73bdd4cbc03bce81b171
--- /dev/null
+++ b/codeflix/codeflix/views.py
@@ -0,0 +1,120 @@
+from django.contrib.auth.models import User
+from django.contrib.sites.shortcuts import get_current_site
+from django.core.exceptions import ValidationError
+from django.shortcuts import resolve_url
+from django.template import loader
+from django.urls import reverse_lazy
+from django.utils.decorators import method_decorator
+from django.utils.encoding import force_bytes
+from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
+from django.utils.translation import gettext_lazy as _
+from django.views.decorators.csrf import csrf_protect
+from django.views.generic import CreateView, TemplateView
+
+from . import settings
+from .forms import SignUpForm
+from .tokens import account_activation_token
+
+# create your views here.
+
+
+class UserCreateView(CreateView):
+    """
+    A view used to register a new user.
+    """
+    email_template_name = 'registration/account_activation_email.html'
+    form_class = SignUpForm
+    success_url = reverse_lazy('account_activation_sent')
+    template_name = 'registration/signup.html'
+    title = _("Sign up")
+    token_generator = account_activation_token
+
+    def form_valid(self, form):
+        """
+        If the form is valid, then the user is created with is_active set to False
+        so that the user cannot log in until the email has been validated.
+        """
+        use_https = self.request.is_secure()
+        user = form.save(commit=False)
+        user.is_active = False
+        user.save()  # Sends a signal to create the corresponding profile object.
+        site = get_current_site(self.request)
+        subject = "Activate your {} account".format(site.name)
+        message = loader.render_to_string('registration/account_activation_email.html',
+                                          {
+                                              'user': user,
+                                              'domain': site.domain,
+                                              'site_name': site.name,
+                                              'protocol': 'https' if use_https else 'http',
+                                              'token': self.token_generator.make_token(user),
+                                              'uid': urlsafe_base64_encode(force_bytes(user.pk)),
+                                          })
+        user.email_user(subject, message)
+        return super().form_valid(form)
+
+
+class UserActivateView(TemplateView):
+    succes_url = reverse_lazy('account_activation_done')
+    title = _("Account Activation")
+
+    @method_decorator(csrf_protect)
+    def dispatch(self, *args, **kwargs):
+        """
+        The dispatch method looks at the request to determine whether it is a GET, POST, etc,
+        and relays the request to a matching method if one is defined, or raises HttpResponseNotAllowed
+        if not. We chose to check the token in the dispatch method to mimic PasswordReset from
+        django.contrib.auth
+        """
+        assert 'uidb64' in kwargs and 'token' in kwargs
+
+        self.validlink = False
+        user = self.get_user(kwargs['uidb64'])
+        token = kwargs['token']
+
+        if user is not None and account_activation_token.check_token(user, token):
+            self.validlink = True
+            user.is_active = True
+            user.profile.email_confirmed = True
+            user.save()
+            return super().dispatch(*args, **kwargs)
+        else:
+            # Display the "Account Activation unsuccessful" page.
+            return self.render_to_response(self.get_context_data())
+
+    def get_user(self, uidb64):
+        try:
+            # urlsafe_base64_decode() decodes to bytestring
+            uid = urlsafe_base64_decode(uidb64).decode()
+            user = User.objects.get(pk=uid)
+        except (TypeError, ValueError, OverflowError, User.DoesNotExist, ValidationError):
+            user = None
+        return user
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        if self.validlink:
+            context['validlink'] = True
+        else:
+            context.update({
+                'title': _('Account Activation unsuccessful'),
+                'validlink': False,
+            })
+        return context
+
+
+class UserActivateDoneView(TemplateView):
+    template_name = 'registration/account_activation_complete.html'
+    title = _('Account activation complte')
+
+    def get_context_data(self, **kwargs):
+        """
+        Provides the template with the login_url.
+        """
+        context = super().get_context_data(**kwargs)
+        context['login_url'] = resolve_url(settings.LOGIN_URL)
+        return context
+
+
+class UserActivationEmailSentView(TemplateView):
+    template_name = 'registration/account_activation_email_sent.html'
+    title = _('Account activation email sent')
diff --git a/codeflix/templates/base.html b/codeflix/templates/base.html
index d4b1511911892349a2ea32bdec69bae6970c4028..ccc8e05ac9ba5216b947b49276719f53f1340aa5 100644
--- a/codeflix/templates/base.html
+++ b/codeflix/templates/base.html
@@ -33,9 +33,10 @@
 	      <li class="nav-item">
 		<a class="nav-link" href="#"> Welcome {{ user.get_username }} </a>
 	      </li>
-		<a class="nav-link" href="{% url 'logout' %}">{% icon "sign-out-alt"%} Logout </a>
+		<a class="nav-link" href="{% url 'logout' %}">{% icon "sign-out-alt"%} Log Out </a>
 		{% else %}
-		<a class="nav-link" href="{% url 'login' %}">{% icon "sign-in-alt" %} Login </a>
+		<a class="nav-link" href="{% url 'signup' %}">{% icon "user-plus" %} Sign Up </a>
+		<a class="nav-link" href="{% url 'login' %}">{% icon "sign-in-alt" %} Log In </a>
 		{% endif %}
 	      </li>
       </ul>
diff --git a/codeflix/templates/registration/account_activation_complete.html b/codeflix/templates/registration/account_activation_complete.html
new file mode 100644
index 0000000000000000000000000000000000000000..5a7a01c99f0a641d990ccdd9dbf4dd85d660377a
--- /dev/null
+++ b/codeflix/templates/registration/account_activation_complete.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+
+{% block content %}
+<h2>Account Activation</h2>
+
+Your account have successfully been activated. You can now <a href="{{ login_url }}">log in</a>.
+
+{% endblock %}
diff --git a/codeflix/templates/registration/account_activation_email.html b/codeflix/templates/registration/account_activation_email.html
new file mode 100644
index 0000000000000000000000000000000000000000..e6fb54a7a4c66d6493af94ef469862315afe1cd2
--- /dev/null
+++ b/codeflix/templates/registration/account_activation_email.html
@@ -0,0 +1,11 @@
+Hi {{ user.username }},
+
+Welcome to {{ site_name }}. Please click on the link below to confirm your registration.
+
+{{ protocol }}://{{ domain }}{% url 'account_activation' uidb64=uid token=token %}
+
+This link is only valid for a couple of days, after that you will need to contact us to validate your email.
+
+Thanks,
+
+{{ site_name }} team.
diff --git a/codeflix/templates/registration/account_activation_email_sent.html b/codeflix/templates/registration/account_activation_email_sent.html
new file mode 100644
index 0000000000000000000000000000000000000000..ddf2d972b02e391c24a906f7acf99698eede88ad
--- /dev/null
+++ b/codeflix/templates/registration/account_activation_email_sent.html
@@ -0,0 +1,7 @@
+{% extends "base.html" %}
+
+{% block content %}
+<h2>Account Activation</h2>
+
+An email has been sent. Please click on the link to activate your account.
+{% endblock %}
diff --git a/codeflix/templates/registration/signup.html b/codeflix/templates/registration/signup.html
new file mode 100644
index 0000000000000000000000000000000000000000..3bad2876433f47becc05d4375650238533859ec6
--- /dev/null
+++ b/codeflix/templates/registration/signup.html
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% load bootstrap4 %}
+
+{% block title %}Sign up{% endblock %}
+
+{% block content %}
+    <form method="post" action="">
+        {% csrf_token %}
+        {% bootstrap_form form %}
+        <button class="btn btn-success" type="submit">
+            <i class="fa fa-sign-in"></i> Sign up
+        </button>
+    </form>
+{% endblock %}