Repository: goauthentik/authentik
File: authentik/core/api/authenticated_sessions.py (Python)

Code before:

class AuthenticatedSessionViewSet(
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    UsedByMixin,
    mixins.ListModelMixin,
    GenericViewSet,
):
    """AuthenticatedSession Viewset"""

    lookup_field = "uuid"
    queryset = AuthenticatedSession.objects.select_related("session").all()
    serializer_class = AuthenticatedSessionSerializer
    search_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
    filterset_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
    ordering = ["user__username"]
    owner_field = "user"

    @action(detail=False, methods=["POST"], pagination_class=None, filter_backends=[])
    def bulk_delete(self, request: Request) -> Response:
        """Bulk revoke all sessions for multiple users"""
        serializer = BulkDeleteSessionSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        user_ids = serializer.validated_data.get("user_ids", [])
        deleted_count, _ = AuthenticatedSession.objects.filter(user_id__in=user_ids).delete()

        return Response({"deleted": deleted_count}, status=200)


Review comment (security):
```suggestion
        user_pks = body.validated_data.get("user_pks", [])
        deleted_count, _ = AuthenticatedSession.objects.filter(user_pk__in=user_pks).delete()
```
With the other changes

Code after:
            "uuid",
            "current",
            "user_agent",
            "geo_ip",
            "asn",
            "user",
            "last_ip",
            "last_user_agent",
            "last_used",
            "expires",
        ]
        extra_args = {"uuid": {"read_only": True}}


class AuthenticatedSessionViewSet(
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    UsedByMixin,
    mixins.ListModelMixin,
    GenericViewSet,
):
    """AuthenticatedSession Viewset"""

    lookup_field = "uuid"
    queryset = AuthenticatedSession.objects.select_related("session").all()
    serializer_class = AuthenticatedSessionSerializer
    search_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
    filterset_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
    ordering = ["user__username"]
    owner_field = "user"

    @permission_required("authentik_core.delete_authenticatedsession")
    @extend_schema(
        parameters=[BulkDeleteSessionSerializer],
        responses={
            200: inline_serializer(
                "BulkDeleteSessionResponse",
                {"deleted": serializers.IntegerField()},
            ),
        },
    )
    @validate(BulkDeleteSessionSerializer, location="query")
    @action(detail=False, methods=["DELETE"], pagination_class=None, filter_backends=[])
    def bulk_delete(self, request: Request, *, query: BulkDeleteSessionSerializer) -> Response:
        """Bulk revoke all sessions for multiple users"""
        user_pks = query.validated_data.get("user_pks", [])
        deleted_count, _ = AuthenticatedSession.objects.filter(user_id__in=user_pks).delete()

        return Response({"deleted": deleted_count}, status=200)