diff --git a/majak/settings/base.py b/majak/settings/base.py
index 3d88cb84a1a98d7866398e75a86009a27a37ab28..2744e99ad1bf05e08b38ed9f5c7811c8878bbf60 100644
--- a/majak/settings/base.py
+++ b/majak/settings/base.py
@@ -15,6 +15,7 @@ INSTALLED_APPS = [
     "search",
     "senator",
     "pirates",
+    "users",
     "wagtail.contrib.forms",
     "wagtail.contrib.redirects",
     "wagtail.contrib.modeladmin",
@@ -139,6 +140,15 @@ WAGTAIL_ALLOW_UNICODE_SLUGS = False
 
 TAGGIT_CASE_INSENSITIVE = True
 
+AUTH_USER_MODEL = "users.User"
+
+WAGTAIL_USER_EDIT_FORM = "users.forms.UserEditForm"
+WAGTAIL_USER_CREATION_FORM = "users.forms.UserCreationForm"
+WAGTAIL_PASSWORD_MANAGEMENT_ENABLED = False
+WAGTAIL_PASSWORD_RESET_ENABLED = False
+WAGTAILUSERS_PASSWORD_ENABLED = False
+WAGTAILUSERS_PASSWORD_REQUIRED = False
+WAGTAIL_EMAIL_MANAGEMENT_ENABLED = False
 
 AUTHENTICATION_BACKENDS = ["pirates.auth.PiratesOIDCAuthenticationBackend"]
 
@@ -150,3 +160,7 @@ OIDC_OP_JWKS_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/certs")
 OIDC_OP_AUTHORIZATION_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/auth")
 OIDC_OP_TOKEN_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/token")
 OIDC_OP_USER_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/userinfo")
+
+LOGIN_REDIRECT_URL = "/admin"
+LOGOUT_REDIRECT_URL = "/admin"
+LOGIN_URL = "/admin"
diff --git a/requirements/base.in b/requirements/base.in
index 2d5e0d1bc72ca173be89c2e547a7fb61239ae505..54fb71790b8b1f7300dda396a4dfc63192a22770 100644
--- a/requirements/base.in
+++ b/requirements/base.in
@@ -3,4 +3,4 @@ wagtailmenus
 django-environ
 django-extensions
 psycopg2-binary
-git+https://gitlab.pirati.cz/to/pirates@v0.2.0
+git+https://gitlab.pirati.cz/to/pirates@v0.2.1
diff --git a/requirements/base.txt b/requirements/base.txt
index 27d6540d02a3948029f506f71cb79b2611f378ba..ed81bff78d66ed2fa51b8554e958d6afdc5cc4bc 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -25,7 +25,7 @@ josepy==1.3.0             # via mozilla-django-oidc
 l18n==2018.5              # via wagtail
 mozilla-django-oidc==1.2.3  # via pirates
 pillow==6.2.2             # via wagtail
-git+https://gitlab.pirati.cz/to/pirates@v0.2.0  # via -r base.in
+git+https://gitlab.pirati.cz/to/pirates@v0.2.1  # via -r base.in
 psycopg2-binary==2.8.5    # via -r base.in
 pyasn1-modules==0.2.8     # via python-ldap
 pyasn1==0.4.8             # via pyasn1-modules, python-ldap
diff --git a/users/__init__.py b/users/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/users/apps.py b/users/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ef1284a08e106b0b8c9720ce3f7420f43be5c9c
--- /dev/null
+++ b/users/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class UsersConfig(AppConfig):
+    name = "users"
diff --git a/users/forms.py b/users/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a8c74785bc5282ab59867bc6d2c58c518194b92
--- /dev/null
+++ b/users/forms.py
@@ -0,0 +1,12 @@
+from django import forms
+from django.contrib.auth import get_user_model
+
+
+class UserCreationForm(forms.ModelForm):
+    class Meta:
+        model = get_user_model()
+
+
+class UserEditForm(forms.ModelForm):
+    class Meta:
+        model = get_user_model()
diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..f39e0799145de8fec1ab3324c5f7b0e194a35717
--- /dev/null
+++ b/users/migrations/0001_initial.py
@@ -0,0 +1,116 @@
+# Generated by Django 3.0.5 on 2020-05-04 16:02
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ("auth", "0011_update_proxy_permissions"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="User",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "is_superuser",
+                    models.BooleanField(
+                        default=False,
+                        help_text="Designates that this user has all permissions without explicitly assigning them.",
+                        verbose_name="superuser status",
+                    ),
+                ),
+                (
+                    "sso_id",
+                    models.CharField(
+                        error_messages={
+                            "unique": "A user with that SSO ID already exists."
+                        },
+                        max_length=150,
+                        unique=True,
+                        verbose_name="SSO ID",
+                    ),
+                ),
+                (
+                    "first_name",
+                    models.CharField(
+                        blank=True, max_length=150, verbose_name="first name"
+                    ),
+                ),
+                (
+                    "last_name",
+                    models.CharField(
+                        blank=True, max_length=150, verbose_name="last name"
+                    ),
+                ),
+                (
+                    "email",
+                    models.EmailField(
+                        blank=True, max_length=254, verbose_name="email address"
+                    ),
+                ),
+                (
+                    "is_staff",
+                    models.BooleanField(
+                        default=False,
+                        help_text="Designates whether the user can log into this admin site.",
+                        verbose_name="staff status",
+                    ),
+                ),
+                (
+                    "is_active",
+                    models.BooleanField(
+                        default=True,
+                        help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
+                        verbose_name="active",
+                    ),
+                ),
+                (
+                    "date_joined",
+                    models.DateTimeField(
+                        default=django.utils.timezone.now, verbose_name="date joined"
+                    ),
+                ),
+                (
+                    "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={
+                "verbose_name": "user",
+                "verbose_name_plural": "users",
+                "abstract": False,
+            },
+        ),
+    ]
diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/users/models.py b/users/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..4004fa15b05e54dcc3a731e566f10a3807af4050
--- /dev/null
+++ b/users/models.py
@@ -0,0 +1,7 @@
+from pirates.models import AbstractUser
+
+
+class User(AbstractUser):
+    def get_username(self):
+        """Used in wagtail templates"""
+        return self.email or self.sso_id
diff --git a/users/templates/wagtailadmin/login.html b/users/templates/wagtailadmin/login.html
new file mode 100644
index 0000000000000000000000000000000000000000..c7a422eaca7b101c73b307fef3fe9609344c7676
--- /dev/null
+++ b/users/templates/wagtailadmin/login.html
@@ -0,0 +1,6 @@
+{% extends "wagtailadmin/login.html" %}
+
+{% block login_form %}
+    <h1>Redakční systém Maják</h1>
+    <a class="button" href="{% url 'oidc_authentication_init' %}">Přihlásit se Pirátskou identitou</a>
+{% endblock %}