diff --git a/homepage/accounts/__init__.py b/homepage/accounts/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/homepage/accounts/admin.py b/homepage/accounts/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/homepage/accounts/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/homepage/accounts/apps.py b/homepage/accounts/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b3fc5a44939430bfb326ca9a33f80e99b06b5be
--- /dev/null
+++ b/homepage/accounts/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+    name = 'accounts'
diff --git a/homepage/accounts/authentication.py b/homepage/accounts/authentication.py
new file mode 100644
index 0000000000000000000000000000000000000000..c6c24a65b4b19c59722f83068f634773b9715fa0
--- /dev/null
+++ b/homepage/accounts/authentication.py
@@ -0,0 +1,23 @@
+import sys
+from accounts.models import ListUser, Token
+
+class PasswordlessAuthenticationBackend(object):
+
+    def authenticate(self, uid):
+        print('uid', uid, file=sys.stderr)
+        if not Token.objects.filter(uid=uid).exists():
+            print('no token found', file=sys.stderr)
+            return None
+        token = Token.objects.get(uid=uid)
+        print('got token', file=sys.stderr)
+        try:
+            user = ListUser.objects.get(email=token.email)
+            print('got user', file=sys.stderr)
+            return user
+        except ListUser.DoesNotExist:
+            print('new user', file=sys.stderr)
+            return ListUser.objects.create(email=token.email)
+
+
+    def get_user(self, email):
+        return ListUser.objects.get(email=email)
\ No newline at end of file
diff --git a/homepage/accounts/models.py b/homepage/accounts/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec1795ac101f9dfedf83d6037c4099a4b8e15013
--- /dev/null
+++ b/homepage/accounts/models.py
@@ -0,0 +1,32 @@
+from django.db import models
+
+class Token(models.Model):
+    email = models.EmailField()
+    uid = models.CharField(max_length=255)
+
+from django.contrib.auth.models import (
+    AbstractBaseUser, BaseUserManager, PermissionsMixin
+)
+
+class ListUserManager(BaseUserManager):
+
+    def create_user(self, email):
+        ListUser.objects.create(email=email)
+
+    def create_superuser(self, email, password):
+        self.create_user(email)
+
+class ListUser(AbstractBaseUser, PermissionsMixin):
+    email = models.EmailField(primary_key=True)
+    USERNAME_FIELD = 'email'
+    #REQUIRED_FIELDS = ['email', 'height']
+
+    objects = ListUserManager()
+
+    @property
+    def is_staff(self):
+        return self.email == 'harry.percival@example.com'
+
+    @property
+    def is_active(self):
+        return True
\ No newline at end of file
diff --git a/homepage/accounts/templates/login_email_sent.html b/homepage/accounts/templates/login_email_sent.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea8ebfcc36fbb8dec7be66a9c85b91a4c0f64b2e
--- /dev/null
+++ b/homepage/accounts/templates/login_email_sent.html
@@ -0,0 +1,7 @@
+<html>
+<h1>Email sent</h1>
+
+<p>Check your email, you'll find a message with a link that will log you into
+the site.</p>
+
+</html>
\ No newline at end of file
diff --git a/homepage/accounts/tests.py b/homepage/accounts/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/homepage/accounts/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/homepage/accounts/urls.py b/homepage/accounts/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..1027713d863150840a87c375d58301fbd5c06ed4
--- /dev/null
+++ b/homepage/accounts/urls.py
@@ -0,0 +1,8 @@
+from django.urls import path
+from accounts import views
+
+urlpatterns = [
+    path('send_email', views.send_login_email, name='send_login_email'),
+    path('login', views.login, name='login'),
+    path('logout', views.logout, name='logout'),
+]
\ No newline at end of file
diff --git a/homepage/accounts/views.py b/homepage/accounts/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e829adb02009a4595eb636c06191e8743bc9802
--- /dev/null
+++ b/homepage/accounts/views.py
@@ -0,0 +1,36 @@
+import uuid
+import sys
+from django.contrib.auth import authenticate
+from django.contrib.auth import login as auth_login, logout as auth_logout
+from django.core.mail import send_mail
+from django.shortcuts import redirect, render
+import os
+
+from accounts.models import Token
+
+
+def send_login_email(request):
+    email = request.POST.get('email')
+    uid = str(uuid.uuid4())
+    Token.objects.create(email=email, uid=uid)
+    print('saving uid', uid, 'for email', email, file=sys.stderr)
+    url = request.build_absolute_uri(f'/accounts/login?uid={uid}')
+    send_mail(
+        'Your login link for Superlists',
+        f'Use this link to log in:\n\n{url}',
+        'noreply@superlists',
+        [email],
+    )
+    return render(request, 'login_email_sent.html')
+
+def login(request):
+    print('login view', file=sys.stderr)
+    uid = request.GET.get('uid')
+    user = authenticate(uid=uid)
+    if user is not None:
+        auth_login(request, user)
+    return redirect('/')
+
+def logout(request):
+    auth_logout(request)
+    return redirect('/')
\ No newline at end of file
diff --git a/homepage/functional_tests/base.py b/homepage/functional_tests/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..f75c65c83e30448283504527f029a505b98cc4f9
--- /dev/null
+++ b/homepage/functional_tests/base.py
@@ -0,0 +1,32 @@
+from django.test import LiveServerTestCase
+from selenium import webdriver
+from selenium.webdriver.chrome.options import Options
+from selenium.webdriver.common.keys import Keys
+import unittest
+import os
+import time
+
+
+class FunctionalTest(LiveServerTestCase):
+    def setUp(self):
+        options = Options()
+        options.add_argument('--dns-prefetch-disable')
+        options.add_argument('--no-sandbox')
+        options.add_argument('--headless')
+        options.add_argument('disable-gpu')
+        self.browser = webdriver.Chrome(executable_path="../chromedriver", options=options)
+        self.base_url = os.getenv("APP_URL")
+
+    def tearDown(self):
+        self.browser.quit()
+
+    def wait_for(self, condition_function):
+        start_time = time.time()
+        while time.time() < start_time + 3:
+            if condition_function():
+                return True
+            else:
+                time.sleep(0.1)
+        raise Exception(
+            'Timeout waiting for {}'.format(condition_function.__name__)
+        )
\ No newline at end of file
diff --git a/homepage/functional_tests/test_login.py b/homepage/functional_tests/test_login.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3e5135d000c6faa791c283824ef628b807ba421
--- /dev/null
+++ b/homepage/functional_tests/test_login.py
@@ -0,0 +1,48 @@
+from django.core import mail
+from selenium.webdriver.common.keys import Keys
+import re
+
+from .base import FunctionalTest
+
+TEST_EMAIL = 'dhanar.santika@google.com'
+SUBJECT = 'Your login link for Superlists'
+
+
+class LoginTest(FunctionalTest):
+
+    def test_can_get_email_link_to_log_in(self):
+        # Edith goes to the awesome superlists site
+        # and notices a "Log in" section in the navbar for the first time
+        # It's telling her to enter her email address, so she does
+        self.browser.get(self.live_server_url)
+        self.browser.find_element_by_name('email').send_keys(TEST_EMAIL)
+        self.browser.find_element_by_name('email').send_keys(Keys.ENTER)
+
+        # A message appears telling her an email has been sent
+        self.wait_for(lambda: self.assertIn(
+            'Check your email',
+            self.browser.find_element_by_tag_name('body').text
+        ))
+
+        # She checks her email and finds a message
+        email = mail.outbox[0]  
+        self.assertIn(TEST_EMAIL, email.to)
+        self.assertEqual(email.subject, SUBJECT)
+
+        # It has a url link in it
+        self.assertIn('Use this link to log in', email.body)
+        url_search = re.search(r'http://.+/.+$', email.body)
+        if not url_search:
+            self.fail(f'Could not find url in email body:\n{email.body}')
+        url = url_search.group(0)
+        self.assertIn(self.live_server_url, url)
+
+        # she clicks it
+        self.browser.get(url)
+
+        # she is logged in!
+        self.wait_for(
+            lambda: self.browser.find_element_by_link_text('Log out')
+        )
+        navbar = self.browser.find_element_by_css_selector('.navbar')
+        self.assertIn(TEST_EMAIL, navbar.text)
\ No newline at end of file
diff --git a/homepage/homepage/settings.py b/homepage/homepage/settings.py
index a1c6a67c4e9ce4671d82f4a4fa9612fbe66e580c..9f95c4e26ed02d7da017ffac8371686f5e6cd579 100644
--- a/homepage/homepage/settings.py
+++ b/homepage/homepage/settings.py
@@ -33,15 +33,38 @@ ALLOWED_HOSTS = ["*"]
 # Application definition
 
 INSTALLED_APPS = [
-    'django.contrib.admin',
+    #'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'todo',
+    'accounts',
 ]
 
+AUTH_USER_MODEL = 'accounts.ListUser'
+AUTHENTICATION_BACKENDS = [
+    'accounts.authentication.PasswordlessAuthenticationBackend',
+]
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'handlers': {
+        'console': {
+            'level': 'DEBUG',
+            'class': 'logging.StreamHandler',
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['console'],
+        },
+    },
+    'root': {'level': 'INFO'},
+}
+
 MIDDLEWARE = [
     'django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
@@ -127,4 +150,10 @@ PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/1.9/howto/static-files/
 STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
-STATIC_URL = '/static/'
\ No newline at end of file
+STATIC_URL = '/static/'
+
+EMAIL_HOST = 'smtp.gmail.com'
+EMAIL_HOST_USER = 'dhanar.santika@gmail.com'
+EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')
+EMAIL_PORT = 587
+EMAIL_USE_TLS = True
\ No newline at end of file
diff --git a/homepage/homepage/urls.py b/homepage/homepage/urls.py
index eb85f594464d76167f3daba8732f5f9a5e1ed679..bfd42cfe6d23af989e8f40d8d511021cc1fd42c3 100644
--- a/homepage/homepage/urls.py
+++ b/homepage/homepage/urls.py
@@ -14,12 +14,15 @@ Including another URLconf
     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 """
 from django.contrib import admin
-from django.urls import path
+from django.urls import path, include
 from home.views import index
 from todo.views import todo
+from django.views.generic import RedirectView
 
 urlpatterns = [
-    path('admin/', admin.site.urls),
-    path("", index, name="index"),
+    #path('admin/', admin.site.urls),
+    #path("", index, name="index"),
+    path("", RedirectView.as_view(url="todo/", permanent="true"), name="index"),
     path("todo/", todo, name="todo"),
+    path("accounts/", include('accounts.urls')),
 ]
diff --git a/homepage/todo/templates/base.html b/homepage/todo/templates/base.html
index 489ab02e4c5504dec35f0c12b519ab73a1442323..ea2b13e8b3cb03694b289551cec21bd18262f8c4 100644
--- a/homepage/todo/templates/base.html
+++ b/homepage/todo/templates/base.html
@@ -12,22 +12,20 @@
 
   <body>
     ​<div class="container">
- 
-      ​<div class="row">
-        <div class="col-md-6 col-md-offset-3 jumbotron">
-            ​<div class="text-center">
-              ​<h1>{% block header_text %}{% endblock %}</h1>
-              ​<form method="POST" action="{% block form_action %}{% endblock %}">
-                ​<input name="item_text" id="id_new_item"
-                ​class="form-control input-lg"
-                ​placeholder="Enter a to-do item" />
-              ​{% csrf_token %}
-            ​</form>
-          ​</div>
-        ​</div>
-      ​</div>
- 
-      ​<div class="row">
+
+      <div class="navbar">
+        {% if user.is_authenticated %}
+          <p>Logged in as {{ user.email }}</p>
+          <p><a id="id_logout" href="{% url 'logout' %}">Log out</a></p>
+        {% else %}
+          <form method="POST" action ="{% url 'send_login_email' %}">
+            Enter email to log in: <input name="email" type="text" />
+            {% csrf_token %}
+          </form>
+        {% endif %}
+      </div>
+  
+      <div class="row">
         ​<div class="col-md-6 col-md-offset-3">
           ​{% block table %}
           ​{% endblock %}