diff --git a/opentech/apply/urls.py b/opentech/apply/urls.py
index a7487aaf5f3d029ec18b832ce8b329a2f6c32052..4624990d07ee3a1c64946e9dc6ab25ea614d4217 100644
--- a/opentech/apply/urls.py
+++ b/opentech/apply/urls.py
@@ -5,5 +5,5 @@ from .users import urls as users_urls
 
 urlpatterns = [
     url(r'^apply/', include(funds_urls)),
-    url(r'^user/', include(users_urls))
+    url(r'^account/', include(users_urls, namespace='users')),
 ]
diff --git a/opentech/apply/users/templates/users/account.html b/opentech/apply/users/templates/users/account.html
new file mode 100644
index 0000000000000000000000000000000000000000..725d615316bb18d3700f3dc45ed61a22253c7ad1
--- /dev/null
+++ b/opentech/apply/users/templates/users/account.html
@@ -0,0 +1,12 @@
+{% extends 'base.html' %}
+{% load i18n %}
+
+{% block title %}Account{% endblock %}
+
+{% block content %}
+<h2>Welcome {{ user }}</h2>
+
+{% if show_change_password %}
+    <a href="{% url 'users:password_change' %}">{% trans "Change password" %}</a>
+{% endif %}
+{% endblock %}
diff --git a/opentech/apply/users/templates/users/change_password.html b/opentech/apply/users/templates/users/change_password.html
new file mode 100644
index 0000000000000000000000000000000000000000..26799c69da341f713f390e9eb7139740fbbb8c1a
--- /dev/null
+++ b/opentech/apply/users/templates/users/change_password.html
@@ -0,0 +1,39 @@
+{% extends 'base.html' %}
+{% load i18n %}
+
+{% block title %}{% trans "Change password" %}{% endblock %}
+
+
+{% block content %}
+    {% if form.non_field_errors %}
+        <div class="messages">
+            <ul>
+                {% for error in form.non_field_errors %}
+                <li class="error">{{ error }}</li>
+                {% endfor %}
+            </ul>
+        </div>
+    {% endif %}
+
+    {% if form.errors %}
+        <div class="messages">
+            {% blocktrans count counter=form.errors.items|length %}
+            Please correct the error below.
+            {% plural %}
+            Please correct the errors below.
+            {% endblocktrans %}
+        </div>
+    {% endif %}
+
+    <form action="{% url 'users:password_change' %}" method="POST" novalidate>
+        {% csrf_token %}
+
+        {% for field in form %}
+            {{ field.errors }}
+            {{ field.label_tag }}
+            {{ field }}
+        {% endfor %}
+
+        <button type="submit">{% trans 'Reset password' %}</button>
+    </form>
+{% endblock %}
diff --git a/opentech/apply/users/templates/users/password_reset/complete.html b/opentech/apply/users/templates/users/password_reset/complete.html
new file mode 100644
index 0000000000000000000000000000000000000000..00740fd926d8ee3539dabbe12f556a5bfd0b9a84
--- /dev/null
+++ b/opentech/apply/users/templates/users/password_reset/complete.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block title %}{% trans "Reset password" %}{% endblock %} {% block content %}
+    <h1>{% trans "Password change successful" %}</h1>
+    <p>
+        <a href="{% url 'users:login' %}">{% trans "Log in" %}</a>
+    </p>
+{% endblock %}
diff --git a/opentech/apply/users/templates/users/password_reset/confirm.html b/opentech/apply/users/templates/users/password_reset/confirm.html
new file mode 100644
index 0000000000000000000000000000000000000000..6371c4593494ca9a49e6bae1d0523b4965e9527a
--- /dev/null
+++ b/opentech/apply/users/templates/users/password_reset/confirm.html
@@ -0,0 +1,25 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block content %}
+    <form method="post" novalidate>
+        {% csrf_token %}
+        <h1>{% trans "Set your new password" %}</h1>
+
+        <ul class="fields">
+            <li>
+                <div class="field">
+                    {{ form.new_password1.label_tag }} {{ form.new_password1 }}
+                </div>
+            </li>
+            <li>
+                <div class="field">
+                    {{ form.new_password2.label_tag }} {{ form.new_password2 }}
+                </div>
+            </li>
+            <li class="submit">
+                <button type="submit">{% trans 'Reset password' %}</button>
+            </li>
+        </ul>
+    </form>
+{% endblock %}
diff --git a/opentech/apply/users/templates/users/password_reset/done.html b/opentech/apply/users/templates/users/password_reset/done.html
new file mode 100644
index 0000000000000000000000000000000000000000..8773bd7acb1b6669ca18489f65aa05c6160c9905
--- /dev/null
+++ b/opentech/apply/users/templates/users/password_reset/done.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block title %}{% trans "Reset password" %}{% endblock %}
+
+{% block content %}
+    <h1>{% trans "Check your email" %}</h1>
+    <p>{% trans "A link to reset your password has been emailed to you." %}</p>
+{% endblock %}
diff --git a/opentech/apply/users/templates/users/password_reset/email.txt b/opentech/apply/users/templates/users/password_reset/email.txt
new file mode 100644
index 0000000000000000000000000000000000000000..30d6aa5aa9ad5f0525d97894a2e11b8e4dbd7c53
--- /dev/null
+++ b/opentech/apply/users/templates/users/password_reset/email.txt
@@ -0,0 +1,7 @@
+{% load i18n wagtailadmin_tags %}{% base_url_setting as base_url %}
+{% trans "Please follow the link below to reset your password:" %}
+{% if base_url %}{{ base_url }}{% else %}{{ protocol }}://{{ domain }}{% endif %}{% url 'users:password_reset_confirm' uidb64=uid token=token %}
+
+{% if user.USERNAME_FIELD != "email" %}
+{% trans "Your username (in case you've forgotten):" %} {{ user.get_username }}
+{% endif %}
diff --git a/opentech/apply/users/templates/users/password_reset/form.html b/opentech/apply/users/templates/users/password_reset/form.html
new file mode 100644
index 0000000000000000000000000000000000000000..e75567ab59e313c9a4715da9b782351b03cacd3a
--- /dev/null
+++ b/opentech/apply/users/templates/users/password_reset/form.html
@@ -0,0 +1,25 @@
+{% extends 'base.html' %}
+{% load i18n %}
+
+{% block title %}{% trans "Reset password" %}{% endblock %}
+
+
+{% block content %}
+    {% if form.non_field_errors %}
+        <div class="messages">
+            <ul>
+                {% for error in form.non_field_errors %}
+                <li class="error">{{ error }}</li>
+                {% endfor %}
+            </ul>
+        </div>
+    {% endif %}
+
+    <form method="post">
+        {% csrf_token %}
+        {{ form.email.label_tag }}
+        {{ form.email }}
+
+        <button type="submit">{% trans 'Reset password' %}</button>
+    </form>
+{% endblock %}
diff --git a/opentech/apply/users/urls.py b/opentech/apply/users/urls.py
index 0185992fa6f5f2f327ac83fbd46abfdb7c4e5c8f..4942e2dada305c2d44cd8b4df19f80b9d882ab6b 100644
--- a/opentech/apply/users/urls.py
+++ b/opentech/apply/users/urls.py
@@ -1,16 +1,56 @@
 from django.conf.urls import url
-
 from django.contrib.auth import views as auth_views
+from django.urls import reverse_lazy
+
+from opentech.apply.users.views import account
 
 urlpatterns = [
-    # TODO replace with dashboard view with a login_required decorator
-    url(r'^$', auth_views.login, {
-        'template_name': 'users/login.html'
-    }, name='user'),
-    url(r'^login$', auth_views.login, {
-        'template_name': 'users/login.html'
-    }, name='login'),
+    url(r'^$', account, name='account'),
+    url(
+        r'^login/$',
+        auth_views.LoginView.as_view(
+            template_name='users/login.html',
+            redirect_authenticated_user=True
+        ),
+        name='login'
+    ),
 
     # Log out
-    url(r'^logout/$', auth_views.logout, {'next_page': '/'}, name='logout'),
+    url(r'^logout/$', auth_views.LogoutView.as_view(next_page='/'), name='logout'),
+
+    # Password change
+    url(
+        r'^password/$',
+        auth_views.PasswordChangeView.as_view(
+            template_name="users/change_password.html",
+            success_url=reverse_lazy('users:account')
+        ),
+        name='password_change',
+    ),
+
+    # Password reset
+    url(r'^reset/$', auth_views.PasswordResetView.as_view(
+        template_name='users/password_reset/form.html',
+        email_template_name='users/password_reset/email.txt',
+        success_url=reverse_lazy('users:password_reset_done')
+    )),
+    url(
+        r'^reset/done/$',
+        auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset/done.html'),
+        name='password_reset_done'
+    ),
+    url(
+        r'^reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
+        auth_views.PasswordResetConfirmView.as_view(
+            template_name='users/password_reset/confirm.html',
+            post_reset_login=True,
+            success_url=reverse_lazy('users:account')
+        ),
+        name='password_reset_confirm'
+    ),
+    url(
+        r'^reset/complete/$',
+        auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset/complete.html'),
+        name='password_reset_complete'
+    ),
 ]
diff --git a/opentech/apply/users/views.py b/opentech/apply/users/views.py
index f4f3c02cd9caaa6853a8e00baf606135d4a5edd8..c531b183ae221c1441c401f0f17f36ff2fe32980 100644
--- a/opentech/apply/users/views.py
+++ b/opentech/apply/users/views.py
@@ -1 +1,14 @@
-# Views placeholder.
+from django.contrib.auth.decorators import login_required
+from django.shortcuts import render
+from django.urls import reverse_lazy
+
+from wagtail.wagtailadmin.views.account import password_management_enabled
+
+
+@login_required(login_url=reverse_lazy('users:login'))
+def account(request):
+    "Account page placeholder view"
+
+    return render(request, 'users/account.html', {
+        'show_change_password': password_management_enabled() and request.user.has_usable_password(),
+    })
diff --git a/opentech/settings/base.py b/opentech/settings/base.py
index 5aaf1a75957fd821d8260707e8c2c7982ee6919b..2693c88cb6f15773507c3866d5e099a9c793f205 100644
--- a/opentech/settings/base.py
+++ b/opentech/settings/base.py
@@ -181,6 +181,7 @@ MEDIA_URL = '/media/'
 
 AUTH_USER_MODEL = 'users.User'
 # TODO populate me with the dashboard URL when ready
+LOGIN_URL = 'users:login'
 LOGIN_REDIRECT_URL = '/'
 
 # Logging