diff --git a/authentik/admin/api/metrics.py b/authentik/admin/api/metrics.py
index ad3943e16..9ed67ff75 100644
--- a/authentik/admin/api/metrics.py
+++ b/authentik/admin/api/metrics.py
@@ -13,7 +13,7 @@ from rest_framework.permissions import IsAdminUser
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import Serializer
-from rest_framework.viewsets import ViewSet
+from rest_framework.viewsets import ReadOnlyModelViewSet
from authentik.events.models import Event, EventAction
@@ -81,7 +81,7 @@ class LoginMetricsSerializer(Serializer):
raise NotImplementedError
-class AdministrationMetricsViewSet(ViewSet):
+class AdministrationMetricsViewSet(ReadOnlyModelViewSet):
"""Login Metrics per 1h"""
permission_classes = [IsAdminUser]
diff --git a/authentik/api/templates/api/swagger.html b/authentik/api/templates/api/swagger.html
index b5e9cc52e..921a25865 100644
--- a/authentik/api/templates/api/swagger.html
+++ b/authentik/api/templates/api/swagger.html
@@ -1,10 +1,12 @@
{% load static %}
+{% load i18n %}
+ {% block title %}{% trans title|default:config.authentik.branding.title %}{% endblock %}
Model:
+ raise NotImplementedError
+
+ def update(self, instance: Model, validated_data: dict) -> Model:
+ raise NotImplementedError
+
+
class UserViewSet(ModelViewSet):
"""User Viewset"""
@@ -50,3 +89,11 @@ class UserViewSet(ModelViewSet):
def me(self, request: Request) -> Response:
"""Get information about current user"""
return Response(UserSerializer(request.user).data)
+
+ @swagger_auto_schema(responses={200: UserMetricsSerializer(many=False)})
+ @action(detail=False)
+ def metrics(self, request: Request) -> Response:
+ """User metrics per 1h"""
+ serializer = UserMetricsSerializer(True)
+ serializer.context["request"] = request
+ return Response(serializer.data)
diff --git a/swagger.yaml b/swagger.yaml
index 0e9790483..ea14438dd 100755
--- a/swagger.yaml
+++ b/swagger.yaml
@@ -24,7 +24,27 @@ paths:
get:
operationId: admin_metrics_list
description: Login Metrics per 1h
- parameters: []
+ parameters:
+ - name: ordering
+ in: query
+ description: Which field to use when ordering the results.
+ required: false
+ type: string
+ - name: search
+ in: query
+ description: A search term.
+ required: false
+ type: string
+ - name: page
+ in: query
+ description: Page Index
+ required: false
+ type: integer
+ - name: page_size
+ in: query
+ description: Page Size
+ required: false
+ type: integer
responses:
'200':
description: Login Metrics per 1h
@@ -33,6 +53,21 @@ paths:
tags:
- admin
parameters: []
+ /admin/metrics/{id}/:
+ get:
+ operationId: admin_metrics_read
+ description: Login Metrics per 1h
+ parameters: []
+ responses:
+ '200':
+ description: ''
+ tags:
+ - admin
+ parameters:
+ - name: id
+ in: path
+ required: true
+ type: string
/admin/system_tasks/:
get:
operationId: admin_system_tasks_list
@@ -1617,6 +1652,54 @@ paths:
tags:
- core
parameters: []
+ /core/users/metrics/:
+ get:
+ operationId: core_users_metrics
+ description: User metrics per 1h
+ parameters:
+ - name: username
+ in: query
+ description: ''
+ required: false
+ type: string
+ - name: name
+ in: query
+ description: ''
+ required: false
+ type: string
+ - name: is_active
+ in: query
+ description: ''
+ required: false
+ type: string
+ - name: ordering
+ in: query
+ description: Which field to use when ordering the results.
+ required: false
+ type: string
+ - name: search
+ in: query
+ description: A search term.
+ required: false
+ type: string
+ - name: page
+ in: query
+ description: Page Index
+ required: false
+ type: integer
+ - name: page_size
+ in: query
+ description: Page Size
+ required: false
+ type: integer
+ responses:
+ '200':
+ description: User Metrics
+ schema:
+ $ref: '#/definitions/UserMetrics'
+ tags:
+ - core
+ parameters: []
/core/users/{id}/:
get:
operationId: core_users_read
@@ -10981,6 +11064,28 @@ definitions:
$ref: '#/definitions/User'
application:
$ref: '#/definitions/Application'
+ UserMetrics:
+ description: User Metrics
+ type: object
+ properties:
+ logins_per_1h:
+ description: ''
+ type: array
+ items:
+ $ref: '#/definitions/Coordinate'
+ readOnly: true
+ logins_failed_per_1h:
+ description: ''
+ type: array
+ items:
+ $ref: '#/definitions/Coordinate'
+ readOnly: true
+ authorizations_per_1h:
+ description: ''
+ type: array
+ items:
+ $ref: '#/definitions/Coordinate'
+ readOnly: true
CertificateKeyPair:
description: CertificateKeyPair Serializer
required:
diff --git a/tests/e2e/test_provider_oauth2_oidc_implicit.py b/tests/e2e/test_provider_oauth2_oidc_implicit.py
index 52bc5664b..e3e207607 100644
--- a/tests/e2e/test_provider_oauth2_oidc_implicit.py
+++ b/tests/e2e/test_provider_oauth2_oidc_implicit.py
@@ -197,6 +197,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
self.container = self.setup_client()
self.driver.get("http://localhost:9009/implicit/")
+ sleep(2)
self.login()
self.wait.until(