diff --git a/contributors/forms.py b/contributors/forms.py
index bd7d1be6367c90f4136831be8f75165e9b458201..056504809d3ddaa4bd9a5c2e9984ff3b0e4555f2 100644
--- a/contributors/forms.py
+++ b/contributors/forms.py
@@ -23,6 +23,16 @@ class RegistrationForm(forms.Form):
     password = forms.CharField(label='password', widget=forms.PasswordInput())
     password_verif = forms.CharField(label='verify pwd', widget=forms.PasswordInput())
 
+class UpdatePersonalDataForm(forms.Form):
+    title = forms.ChoiceField(choices=TITLE_CHOICES)
+    first_name = forms.CharField(label='First name', max_length=100)
+    last_name = forms.CharField(label='Last name', max_length=100)
+    email = forms.EmailField(label='email')
+    orcid_id = forms.CharField(label="ORCID id", max_length=20, required=False)
+    affiliation = forms.CharField(label='Affiliation', max_length=300)
+    address = forms.CharField(label='Address', max_length=1000, required=False)
+    personalwebpage = forms.URLField(label='Personal web page', required=False)
+
 class VetRegistrationForm(forms.Form):
     promote_to_rank_1 = forms.BooleanField(required=False)
     refusal_reason = forms.ChoiceField(choices=REGISTRATION_REFUSAL_CHOICES, required=False)
@@ -32,4 +42,8 @@ class AuthenticationForm(forms.Form):
     username = forms.CharField(label='username', max_length=100)
     password = forms.CharField(label='password', widget=forms.PasswordInput())
 
+class PasswordChangeForm(forms.Form):
+    password_prev = forms.CharField(label='Existing password', widget=forms.PasswordInput())
+    password_new = forms.CharField(label='New password', widget=forms.PasswordInput())
+    password_verif = forms.CharField(label='Reenter new password', widget=forms.PasswordInput())
 
diff --git a/contributors/templates/contributors/change_password.html b/contributors/templates/contributors/change_password.html
new file mode 100644
index 0000000000000000000000000000000000000000..3c3da05514d6dd441756ee45c39f1cf1847ee060
--- /dev/null
+++ b/contributors/templates/contributors/change_password.html
@@ -0,0 +1,23 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: change password{% endblock pagetitle %}
+
+{% block bodysup %}
+
+<section>
+  <h1>Change your SciPost password</h1>
+  <form action="{% url 'contributors:change_password' %}" method="post">
+    {% csrf_token %}
+    <table>
+      <ul>
+	{{ form.as_table }}
+      </ul>
+    </table>
+    <input type="submit" value="Change" />
+  </form>
+  {% if errormessage %}
+  <p>{{ errormessage }}</p>
+  {% endif %}
+</section>
+
+{% endblock bodysup %}
diff --git a/contributors/templates/contributors/change_password_ack.html b/contributors/templates/contributors/change_password_ack.html
new file mode 100644
index 0000000000000000000000000000000000000000..8b194e605d0eaa25494edad17885e0bb0b6acbce
--- /dev/null
+++ b/contributors/templates/contributors/change_password_ack.html
@@ -0,0 +1,11 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: password changed{% endblock pagetitle %}
+
+{% block bodysup %}
+
+<section>
+  <h1>Your SciPost password has been successfully changed</h1>
+</section>
+
+{% endblock bodysup %}
diff --git a/contributors/templates/contributors/personal_page.html b/contributors/templates/contributors/personal_page.html
index f6c6d8b1586c5819803be78621f2ef0607e25970..fe76f74d559f5c686fee97f003dba48b2d2fd208 100644
--- a/contributors/templates/contributors/personal_page.html
+++ b/contributors/templates/contributors/personal_page.html
@@ -62,6 +62,9 @@
 {% if contributor.rank > 0 %}
 <section>
   <h1>Your SciPost Account</h1>
+  <ul>
+    <li><a href="{% url 'contributors:change_password' %}">Change your password</a></li>
+  </ul>
   <hr>
   <div class="row">
     <div class="col-3">
diff --git a/contributors/urls.py b/contributors/urls.py
index c0d87df2c7370fd03f70d72a859fc3aeee3b95df..812c540708a8972adeecfea37a0bcb6ccefed1b7 100644
--- a/contributors/urls.py
+++ b/contributors/urls.py
@@ -12,4 +12,6 @@ urlpatterns = [
     url(r'^login$', views.login_view, name='login'),
     url(r'^logout$', views.logout_view, name='logout'),
     url(r'^personal_page$', views.personal_page, name='personal_page'),
+    url(r'^change_password$', views.change_password, name='change_password'),
+    url(r'^change_password_ack$', views.change_password_ack, name='change_password_ack'),
 ]
diff --git a/contributors/views.py b/contributors/views.py
index 3270154b91a600365f5ab03e418a66e30f11fb6f..f7b5b0949724fdf0b9a1731d5bab94013829043d 100644
--- a/contributors/views.py
+++ b/contributors/views.py
@@ -156,4 +156,25 @@ def personal_page(request):
         context = {'form': form}
         return render(request, 'contributors/login.html', context)
 
+@csrf_protect
+def change_password(request):
+    if request.user.is_authenticated and request.method == 'POST':
+        form = PasswordChangeForm(request.POST)
+        if form.is_valid():
+            # verify existing password:
+            if not request.user.check_password(form.cleaned_data['password_prev']):
+                return render(request, 'contributors/change_password.html', {'form': form, 'errormessage': 'The currently existing password you entered is incorrect'})
+            # check for mismatching new passwords
+            if form.cleaned_data['password_new'] != form.cleaned_data['password_verif']:
+                return render(request, 'contributors/change_password.html', {'form': form, 'errormessage': 'Your new password entries must match'})
+            # otherwise simply change the pwd:
+            request.user.set_password(form.cleaned_data['password_new'])
+            request.user.save()
+            return render(request, 'contributors/change_password_ack.html')
+    else:
+        form = PasswordChangeForm()
+    return render (request, 'contributors/change_password.html', {'form': form})
 
+@csrf_protect
+def change_password_ack(request):
+    return render (request, 'contributors/change_password_ack.html')