diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py
index 9e2a185c803e2db795327b9dd76a6c5891a9214c..a739c1e384ef78f95f5a4b827e5f3d3c4227729c 100644
--- a/api/funkwhale_api/users/models.py
+++ b/api/funkwhale_api/users/models.py
@@ -72,9 +72,12 @@ class User(AbstractUser):
             perms[p] = v
         return perms
 
-    def has_permissions(self, *perms):
+    def has_permissions(self, *perms, operator='and'):
+        if operator not in ['and', 'or']:
+            raise ValueError('Invalid operator {}'.format(operator))
         permissions = self.get_permissions()
-        return all([permissions[p] for p in perms])
+        checker = all if operator == 'and' else any
+        return checker([permissions[p] for p in perms])
 
     def get_absolute_url(self):
         return reverse('users:detail', kwargs={'username': self.username})
diff --git a/api/funkwhale_api/users/permissions.py b/api/funkwhale_api/users/permissions.py
index 2ff49ff3fa6661aecd0616fdb87b5b43f89a95c2..146bc5e1c2ffae96ce7ae448496b69e2194522aa 100644
--- a/api/funkwhale_api/users/permissions.py
+++ b/api/funkwhale_api/users/permissions.py
@@ -16,4 +16,6 @@ class HasUserPermission(BasePermission):
             return False
         if request.user.is_anonymous:
             return False
-        return request.user.has_permissions(*view.required_permissions)
+        operator = getattr(view, 'permission_operator', 'and')
+        return request.user.has_permissions(
+            *view.required_permissions, operator=operator)
diff --git a/api/tests/conftest.py b/api/tests/conftest.py
index d6b1c0204e906b7fe073c4794adccdc00430928c..7caff2009974143584621a2d6f9e2239e622430a 100644
--- a/api/tests/conftest.py
+++ b/api/tests/conftest.py
@@ -231,8 +231,9 @@ def authenticated_actor(factories, mocker):
 
 @pytest.fixture
 def assert_user_permission():
-    def inner(view, permissions):
+    def inner(view, permissions, operator='and'):
         assert HasUserPermission in view.permission_classes
+        assert getattr(view, 'permission_operator', 'and') == operator
         assert set(view.required_permissions) == set(permissions)
     return inner
 
diff --git a/api/tests/users/test_models.py b/api/tests/users/test_models.py
index 49199e0a781b990268431f109ac0c8804f8391ea..44574480242e10cd69c7afb05ad3d2621d738033 100644
--- a/api/tests/users/test_models.py
+++ b/api/tests/users/test_models.py
@@ -47,6 +47,17 @@ def test_get_permissions_regular(factories):
     ({'permission_library': True}, ['library'], True),
     ({'permission_library': True}, ['library', 'federation'], False),
 ])
-def test_has_permissions(args, perms, expected, factories):
+def test_has_permissions_and(args, perms, expected, factories):
     user = factories['users.User'](**args)
-    assert user.has_permissions(*perms) is expected
+    assert user.has_permissions(*perms, operator='and') is expected
+
+
+@pytest.mark.parametrize('args,perms,expected', [
+    ({'is_superuser': True}, ['federation', 'library'], True),
+    ({'is_superuser': False}, ['federation'], False),
+    ({'permission_library': True}, ['library', 'federation'], True),
+    ({'permission_library': True}, ['federation'], False),
+])
+def test_has_permissions_or(args, perms, expected, factories):
+    user = factories['users.User'](**args)
+    assert user.has_permissions(*perms, operator='or') is expected
diff --git a/api/tests/users/test_permissions.py b/api/tests/users/test_permissions.py
index 1564c761db59239eee5169bffd6ee92c2c148301..518ccd1c803038cf0ab5c38a1438b44ef53c1180 100644
--- a/api/tests/users/test_permissions.py
+++ b/api/tests/users/test_permissions.py
@@ -39,7 +39,7 @@ def test_has_user_permission_logged_in_single(value, factories, api_request):
     (False, False, False),
     (True, True, True),
 ])
-def test_has_user_permission_logged_in_single(
+def test_has_user_permission_logged_in_multiple_and(
         federation, library, expected, factories, api_request):
     user = factories['users.User'](
         permission_federation=federation,
@@ -48,9 +48,35 @@ def test_has_user_permission_logged_in_single(
 
     class View(APIView):
         required_permissions = ['federation', 'library']
+        permission_operator = 'and'
     view = View()
     permission = permissions.HasUserPermission()
     request = api_request.get('/')
     setattr(request, 'user', user)
     result = permission.has_permission(request, view)
     assert result == user.has_permissions('federation', 'library') == expected
+
+
+@pytest.mark.parametrize('federation,library,expected', [
+    (True, False, True),
+    (False, True, True),
+    (False, False, False),
+    (True, True, True),
+])
+def test_has_user_permission_logged_in_multiple_or(
+        federation, library, expected, factories, api_request):
+    user = factories['users.User'](
+        permission_federation=federation,
+        permission_library=library,
+    )
+
+    class View(APIView):
+        required_permissions = ['federation', 'library']
+        permission_operator = 'or'
+    view = View()
+    permission = permissions.HasUserPermission()
+    request = api_request.get('/')
+    setattr(request, 'user', user)
+    result = permission.has_permission(request, view)
+    assert result == user.has_permissions(
+        'federation', 'library', operator='or') == expected