diff --git a/accounts/__init__.py b/accounts/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/accounts/admin.py b/accounts/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/accounts/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/accounts/apps.py b/accounts/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b3fc5a44939430bfb326ca9a33f80e99b06b5be
--- /dev/null
+++ b/accounts/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+    name = 'accounts'
diff --git a/accounts/authentication.py b/accounts/authentication.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa4af7bf582cb3c73eef1f50de4cb8b37b1233e8
--- /dev/null
+++ b/accounts/authentication.py
@@ -0,0 +1,23 @@
+import sys
+from accounts.models import ListUser, Token
+
+class PasswordlessAuthenticationBackend(object):
+
+    def authenticate(self, request, 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/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc2c83aaaed1485df1caa4321df51c4e2b5c887f
--- /dev/null
+++ b/accounts/migrations/0001_initial.py
@@ -0,0 +1,37 @@
+# Generated by Django 2.2.5 on 2019-11-13 05:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('auth', '0011_update_proxy_permissions'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Token',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('email', models.EmailField(max_length=254)),
+                ('uid', models.CharField(max_length=255)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='ListUser',
+            fields=[
+                ('password', models.CharField(max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+                ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+                ('email', models.EmailField(max_length=254, primary_key=True, serialize=False)),
+                ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
+                ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
+    ]
diff --git a/accounts/migrations/__init__.py b/accounts/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/accounts/models.py b/accounts/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a0bababc5580e4afe06b24a4e17545d77225bb4
--- /dev/null
+++ b/accounts/models.py
@@ -0,0 +1,30 @@
+from django.db import models
+from django.contrib.auth.models import (
+    AbstractBaseUser, BaseUserManager, PermissionsMixin
+)
+class Token(models.Model):
+    email = models.EmailField()
+    uid = models.CharField(max_length=255)
+
+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/accounts/templates/login_email_sent.html b/accounts/templates/login_email_sent.html
new file mode 100644
index 0000000000000000000000000000000000000000..2aa6e4ffd35016363271165018e8bbc5dfa387f9
--- /dev/null
+++ b/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/accounts/tests.py b/accounts/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/accounts/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/accounts/urls.py b/accounts/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..10f0e241ced16c3e23ac731cc40a705c2d33ec0d
--- /dev/null
+++ b/accounts/urls.py
@@ -0,0 +1,8 @@
+from django.conf.urls import url
+from accounts import views
+
+urlpatterns = [
+    url(r'^send_email$', views.send_login_email, name='send_login_email'),
+    url(r'^login$', views.login, name='login'),
+    url(r'^logout$', views.logout, name='logout'),
+]
\ No newline at end of file
diff --git a/accounts/views.py b/accounts/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..5175fced753bd7f06de4dbb7ae99dffc240edc8c
--- /dev/null
+++ b/accounts/views.py
@@ -0,0 +1,37 @@
+from django.shortcuts import render
+
+# Create your views here.
+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
+from accounts.models import Token
+
+
+def send_login_email(request):
+    email = request.POST['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/chromedriver.exe b/chromedriver.exe
new file mode 100644
index 0000000000000000000000000000000000000000..6ab0ba96397679161e50ad516c7ef4159878e943
Binary files /dev/null and b/chromedriver.exe differ