diff --git a/config/settings/common.py b/config/settings/common.py
index 1af80e943483ef4587b9db507b78e6e4f8b8f88e..a176a4d1bc93a84fd19290e5b3a4c1991948e29a 100644
--- a/config/settings/common.py
+++ b/config/settings/common.py
@@ -271,11 +271,12 @@ CORS_ORIGIN_ALLOW_ALL = True
 #     'funkwhale.localhost',
 # )
 CORS_ALLOW_CREDENTIALS = True
+API_AUTHENTICATION_REQUIRED = env.bool("API_AUTHENTICATION_REQUIRED", True)
 REST_FRAMEWORK = {
     'DEFAULT_PERMISSION_CLASSES': (
         'rest_framework.permissions.IsAuthenticated',
     ),
-    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
+    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
     'PAGE_SIZE': 25,
 
     'DEFAULT_AUTHENTICATION_CLASSES': (
diff --git a/funkwhale_api/common/__init__.py b/funkwhale_api/common/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/funkwhale_api/common/permissions.py b/funkwhale_api/common/permissions.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f13b2005cafc3d9ffcd1f098b5d10e6f080e720
--- /dev/null
+++ b/funkwhale_api/common/permissions.py
@@ -0,0 +1,11 @@
+from django.conf import settings
+
+from rest_framework.permissions import BasePermission
+
+
+class ConditionalAuthentication(BasePermission):
+
+    def has_permission(self, request, view):
+        if settings.API_AUTHENTICATION_REQUIRED:
+            return request.user and request.user.is_authenticated()
+        return True
diff --git a/funkwhale_api/favorites/tests/test_favorites.py b/funkwhale_api/favorites/tests/test_favorites.py
index 9918c67071079065f2f4ab9c8699edc9617bfada..1182222b1a4b9a0dc69cdb82a5a2dea9988df89a 100644
--- a/funkwhale_api/favorites/tests/test_favorites.py
+++ b/funkwhale_api/favorites/tests/test_favorites.py
@@ -66,3 +66,24 @@ class TestFavorites(TestCase):
 
         self.assertEqual(response.status_code, 204)
         self.assertEqual(TrackFavorite.objects.count(), 0)
+
+    from funkwhale_api.users.models import User
+
+    def test_can_restrict_api_views_to_authenticated_users(self):
+        urls = [
+            ('api:favorites:tracks-list', 'get'),
+        ]
+
+        for route_name, method in urls:
+            url = self.reverse(route_name)
+            with self.settings(API_AUTHENTICATION_REQUIRED=True):
+                response = getattr(self.client, method)(url)
+            self.assertEqual(response.status_code, 401)
+
+        self.client.login(username=self.user.username, password='test')
+
+        for route_name, method in urls:
+            url = self.reverse(route_name)
+            with self.settings(API_AUTHENTICATION_REQUIRED=False):
+                response = getattr(self.client, method)(url)
+            self.assertEqual(response.status_code, 200)
diff --git a/funkwhale_api/favorites/views.py b/funkwhale_api/favorites/views.py
index edcb00f2b2acd5e1713c60a64e345ea7608fc995..dc8098bba0a7947751adec39ffde8280af7b12b1 100644
--- a/funkwhale_api/favorites/views.py
+++ b/funkwhale_api/favorites/views.py
@@ -3,6 +3,7 @@ from rest_framework import status
 from rest_framework.response import Response
 
 from funkwhale_api.music.models import Track
+from funkwhale_api.common.permissions import ConditionalAuthentication
 
 from . import models
 from . import serializers
@@ -14,7 +15,9 @@ class TrackFavoriteViewSet(mixins.CreateModelMixin,
 
     serializer_class = serializers.UserTrackFavoriteSerializer
     queryset = models.TrackFavorite.objects.all()
+    permission_classes = [ConditionalAuthentication]
 
+    
     def create(self, request, *args, **kwargs):
         serializer = self.get_serializer(data=request.data)
         serializer.is_valid(raise_exception=True)
diff --git a/funkwhale_api/history/views.py b/funkwhale_api/history/views.py
index 317ca78c2270bb5a1907675c8c1a0c108a383987..d65a70f8742ee958d728738dc1c9aa88c0c457c0 100644
--- a/funkwhale_api/history/views.py
+++ b/funkwhale_api/history/views.py
@@ -4,6 +4,7 @@ from rest_framework.response import Response
 from rest_framework.decorators import detail_route
 
 from funkwhale_api.music.serializers import TrackSerializerNested
+from funkwhale_api.common.permissions import ConditionalAuthentication
 
 from . import models
 from . import serializers
@@ -14,11 +15,11 @@ class ListeningViewSet(mixins.CreateModelMixin,
 
     serializer_class = serializers.ListeningSerializer
     queryset = models.Listening.objects.all()
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
 
     def create(self, request, *args, **kwargs):
         return super().create(request, *args, **kwargs)
-        
+
     def get_queryset(self):
         queryset = super().get_queryset()
         if self.request.user.is_authenticated():
diff --git a/funkwhale_api/music/tests/test_api.py b/funkwhale_api/music/tests/test_api.py
index d4a1c14ba2a4eb1fdda303cd6dd9f8cb69d2c7c5..36c1fa617eecde69a5362ed8ed42c7c39c1d4678 100644
--- a/funkwhale_api/music/tests/test_api.py
+++ b/funkwhale_api/music/tests/test_api.py
@@ -139,3 +139,26 @@ class TestAPI(TMPDirTestCaseMixin, TestCase):
         response = self.client.get(url + '?query={0}'.format(query))
 
         self.assertJSONEqual(expected, json.loads(response.content.decode('utf-8')))
+
+    def test_can_restrict_api_views_to_authenticated_users(self):
+        urls = [
+            ('api:tags-list', 'get'),
+            ('api:tracks-list', 'get'),
+            ('api:artists-list', 'get'),
+            ('api:albums-list', 'get'),
+        ]
+
+        for route_name, method in urls:
+            url = self.reverse(route_name)
+            with self.settings(API_AUTHENTICATION_REQUIRED=True):
+                response = getattr(self.client, method)(url)
+            self.assertEqual(response.status_code, 401)
+
+        user = User.objects.create_user(username='test', email='test@test.com', password='test')
+        self.client.login(username=user.username, password='test')
+
+        for route_name, method in urls:
+            url = self.reverse(route_name)
+            with self.settings(API_AUTHENTICATION_REQUIRED=False):
+                response = getattr(self.client, method)(url)
+            self.assertEqual(response.status_code, 200)
diff --git a/funkwhale_api/music/views.py b/funkwhale_api/music/views.py
index 971fbd72d6bae82c35bc8aea344b08dbd85cc5ec..6622b1e1d8181015e3097bcb062f64874d9aa6e8 100644
--- a/funkwhale_api/music/views.py
+++ b/funkwhale_api/music/views.py
@@ -11,6 +11,7 @@ from django.contrib.auth.decorators import login_required
 from django.utils.decorators import method_decorator
 
 from funkwhale_api.musicbrainz import api
+from funkwhale_api.common.permissions import ConditionalAuthentication
 from taggit.models import Tag
 
 from . import models
@@ -40,14 +41,14 @@ class TagViewSetMixin(object):
 class ArtistViewSet(SearchMixin, viewsets.ReadOnlyModelViewSet):
     queryset = models.Artist.objects.all().order_by('-creation_date').prefetch_related('albums__tracks__files', 'albums__tracks__tags')
     serializer_class = serializers.ArtistSerializerNested
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
     search_fields = ['name']
     ordering_fields = ('creation_date',)
 
 class AlbumViewSet(SearchMixin, viewsets.ReadOnlyModelViewSet):
     queryset = models.Album.objects.all().order_by('-creation_date').prefetch_related('tracks__tags')
     serializer_class = serializers.AlbumSerializerNested
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
     search_fields = ['title']
     ordering_fields = ('creation_date',)
 
@@ -64,15 +65,14 @@ class TrackViewSet(TagViewSetMixin, SearchMixin, viewsets.ReadOnlyModelViewSet):
     """
     queryset = models.Track.objects.all().select_related('album__artist', 'artist').prefetch_related('files')
     serializer_class = serializers.TrackSerializerNested
-    permission_classes = []
-    authentication_classes = []
+    permission_classes = [ConditionalAuthentication]
     search_fields = ['title', 'artist__name']
     ordering_fields = ('creation_date',)
 
 class TagViewSet(viewsets.ReadOnlyModelViewSet):
     queryset = Tag.objects.all()
     serializer_class = serializers.TagSerializer
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
 
 
 class Search(views.APIView):
diff --git a/funkwhale_api/musicbrainz/views.py b/funkwhale_api/musicbrainz/views.py
index d6d8d38cf3afbafa1ba99452d111cd4e53e7963e..21b2d888e13368791c59b76c443f35929f2228f1 100644
--- a/funkwhale_api/musicbrainz/views.py
+++ b/funkwhale_api/musicbrainz/views.py
@@ -3,19 +3,20 @@ from rest_framework.views import APIView
 from rest_framework.response import Response
 from rest_framework.decorators import list_route
 
+from funkwhale_api.common.permissions import ConditionalAuthentication
+
+
 from .client import api
 
 
 class ReleaseDetail(APIView):
-    authentication_classes = []
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
     def get(self, request, *args, **kwargs):
         result = api.releases.get(id=kwargs['uuid'], includes=['artists', 'recordings'])
         return Response(result)
 
 class SearchViewSet(viewsets.ViewSet):
-    authentication_classes = []
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
 
     @list_route(methods=['get'])
     def recordings(self, request, *args, **kwargs):
diff --git a/funkwhale_api/providers/youtube/views.py b/funkwhale_api/providers/youtube/views.py
index 8a4155175c04dd2221747923742b8475b4c99d22..9e909d706227aee6599bd2ba46394c1a60d63552 100644
--- a/funkwhale_api/providers/youtube/views.py
+++ b/funkwhale_api/providers/youtube/views.py
@@ -1,11 +1,11 @@
 from rest_framework.views import APIView
 from rest_framework.response import Response
+from funkwhale_api.common.permissions import ConditionalAuthentication
 
 from .client import client
 
 class APISearch(APIView):
-    authentication_classes = []
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
 
     def get(self, request, *args, **kwargs):
         results = client.search(request.GET['query'])
diff --git a/funkwhale_api/radios/views.py b/funkwhale_api/radios/views.py
index 37874d0e10ae9ec3ebd728cb75b2dccc2d7961d3..1ae788fcb0aad9c2d787f8f4862ff8bf3782d899 100644
--- a/funkwhale_api/radios/views.py
+++ b/funkwhale_api/radios/views.py
@@ -4,6 +4,7 @@ from rest_framework.response import Response
 from rest_framework.decorators import detail_route
 
 from funkwhale_api.music.serializers import TrackSerializerNested
+from funkwhale_api.common.permissions import ConditionalAuthentication
 
 from . import models
 from . import serializers
@@ -14,7 +15,7 @@ class RadioSessionViewSet(mixins.CreateModelMixin,
 
     serializer_class = serializers.RadioSessionSerializer
     queryset = models.RadioSession.objects.all()
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
 
     def get_queryset(self):
         queryset = super().get_queryset()
@@ -36,7 +37,7 @@ class RadioSessionTrackViewSet(mixins.CreateModelMixin,
                                viewsets.GenericViewSet):
     serializer_class = serializers.RadioSessionTrackSerializer
     queryset = models.RadioSessionTrack.objects.all()
-    permission_classes = []
+    permission_classes = [ConditionalAuthentication]
 
     def create(self, request, *args, **kwargs):
         serializer = self.get_serializer(data=request.data)
diff --git a/test.yml b/test.yml
index dc50a9b545d75382531f2684de6cb7ed3925be78..c28a8138c6707205cd28d69846a8e60603920c90 100644
--- a/test.yml
+++ b/test.yml
@@ -6,3 +6,4 @@ test:
     - .:/app
   environment:
     - DJANGO_SETTINGS_MODULE=config.settings.test
+    - API_AUTHENTICATION_REQUIRED=False