Repository: goauthentik/authentik

Issue:
API: Application Pagination only works when user is superuser and { superuser_full_list: true } is passed to the API
**Describe the bug**

This works:

`/api/v3/core/applications/?ordering=name&page=7&page_size=20&search=&superuser_full_list=true`

This does not:

`/api/v3/core/applications/?ordering=name&page=7&page_size=20&search=`

If you pass a page request and do not set `superuser_full_list` _or_ you are not an admin user, you will always only get the first page of results from the Application API for authentik.

**Expected behavior**

The `page=` argument should be respected by the API under all circumstances.

**Version and Deployment (please complete the following information):**

-   authentik version: post-2024.2, commit 2196bde820c4f59a128483670960971df073b076
-   Deployment: authentik [full development environment](https://docs.goauthentik.io/developer-docs/setup/full-dev-environment)


Discussion:

Resolving patch:
diff --git a/authentik/core/api/applications.py b/authentik/core/api/applications.py
--- a/authentik/core/api/applications.py
+++ b/authentik/core/api/applications.py
@@ -22,6 +22,7 @@
 from structlog.stdlib import get_logger
 
 from authentik.admin.api.metrics import CoordinateSerializer
+from authentik.api.pagination import Pagination
 from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
 from authentik.core.api.providers import ProviderSerializer
 from authentik.core.api.used_by import UsedByMixin
@@ -43,9 +44,12 @@
 LOGGER = get_logger()
 
 
-def user_app_cache_key(user_pk: str) -> str:
+def user_app_cache_key(user_pk: str, page_number: int | None = None) -> str:
     """Cache key where application list for user is saved"""
-    return f"{CACHE_PREFIX}/app_access/{user_pk}"
+    key = f"{CACHE_PREFIX}/app_access/{user_pk}"
+    if page_number:
+        key += f"/{page_number}"
+    return key
 
 
 class ApplicationSerializer(ModelSerializer):
@@ -213,7 +217,8 @@ def list(self, request: Request) -> Response:
             return super().list(request)
 
         queryset = self._filter_queryset_for_list(self.get_queryset())
-        paginated_apps = self.paginate_queryset(queryset)
+        paginator: Pagination = self.paginator
+        paginated_apps = paginator.paginate_queryset(queryset, request)
 
         if "for_user" in request.query_params:
             try:
@@ -235,12 +240,14 @@ def list(self, request: Request) -> Response:
         if not should_cache:
             allowed_applications = self._get_allowed_applications(paginated_apps)
         if should_cache:
-            allowed_applications = cache.get(user_app_cache_key(self.request.user.pk))
+            allowed_applications = cache.get(
+                user_app_cache_key(self.request.user.pk, paginator.page.number)
+            )
             if not allowed_applications:
-                LOGGER.debug("Caching allowed application list")
+                LOGGER.debug("Caching allowed application list", page=paginator.page.number)
                 allowed_applications = self._get_allowed_applications(paginated_apps)
                 cache.set(
-                    user_app_cache_key(self.request.user.pk),
+                    user_app_cache_key(self.request.user.pk, paginator.page.number),
                     allowed_applications,
                     timeout=86400,
                 )


Test patch: