diff --git a/bookwyrm/templates/403.html b/bookwyrm/templates/403.html
new file mode 100644
index 000000000..0b78bc6b8
--- /dev/null
+++ b/bookwyrm/templates/403.html
@@ -0,0 +1,20 @@
+{% extends 'layout.html' %}
+{% load i18n %}
+{% load utilities %}
+
+{% block title %}{% trans "Oh no!" %}{% endblock %}
+
+{% block content %}
+
+
{% trans "Permission Denied" %}
+
+ {% blocktrans trimmed with level=request.user|get_user_permission %}
+ You do not have permission to view this page or perform this action. Your user permission level is {{ level }}
.
+ {% endblocktrans %}
+
+
{% trans "If you think you should have access, please speak to your BookWyrm server administrator." %}
+
+
+
+{% endblock %}
+
diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py
index 2fd99403f..76e5d988f 100644
--- a/bookwyrm/templatetags/utilities.py
+++ b/bookwyrm/templatetags/utilities.py
@@ -128,6 +128,13 @@ def id_to_username(user_id):
return value
+@register.filter(name="get_user_permission")
+def get_user_permission(user):
+ """given a user, return their permission level"""
+
+ return user.groups.first() or "User"
+
+
@register.filter(name="is_instance_admin")
def is_instance_admin(localname):
"""Returns a boolean indicating whether the user is the instance admin account"""
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py
index 8541f4fb6..0b65018cf 100644
--- a/bookwyrm/urls.py
+++ b/bookwyrm/urls.py
@@ -792,3 +792,6 @@ urlpatterns.extend(staticfiles_urlpatterns())
# pylint: disable=invalid-name
handler500 = "bookwyrm.views.server_error"
+
+# pylint: disable=invalid-name
+handler403 = "bookwyrm.views.permission_denied"
diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py
index 2d2e97f52..63f9d54b5 100644
--- a/bookwyrm/views/__init__.py
+++ b/bookwyrm/views/__init__.py
@@ -167,3 +167,4 @@ from .annual_summary import (
summary_revoke_key,
)
from .server_error import server_error
+from .permission_denied import permission_denied
diff --git a/bookwyrm/views/permission_denied.py b/bookwyrm/views/permission_denied.py
new file mode 100644
index 000000000..9e62b0933
--- /dev/null
+++ b/bookwyrm/views/permission_denied.py
@@ -0,0 +1,15 @@
+"""custom 403 handler to enable context processors"""
+
+from django.http import HttpResponse
+from django.template.response import TemplateResponse
+
+from .helpers import is_api_request
+
+
+def permission_denied(request, exception): # pylint: disable=unused-argument
+ """permission denied page"""
+
+ if request.method == "POST" or is_api_request(request):
+ return HttpResponse(status=403)
+
+ return TemplateResponse(request, "403.html")