diff --git a/README.md b/README.md
index 1810c114a571461cb24264395767872b50f1acc0..dbde8630bf1579e99180cc7425540a82c64efd96 100644
--- a/README.md
+++ b/README.md
@@ -228,3 +228,29 @@ that the input data is passed in binary form as `.tar` file in the request.
 
 - `HTTP OK [200]` indicating a successful operation, the body of the response includes either the ban information as a
   JSON if it exists or an empty JSON `{}` if a ban with given ID doesn't exist
+
+### Heuristic page
+
+Provides information about user authentication events gathered by AuthEventLogging microservice, to confirm theirs identity.
+
+<br></br>
+**Endpoint:** `/HeuristicGetID`
+
+**Description:** Used to gather ID of searched user
+
+**Result:**
+
+- `HHTP OK [200]` indicating successfull load of search page
+
+<br></br>
+**Endpoint:** `/GetHeuristic`
+
+**Method:** `GET`
+
+**Description:** Used for showing gathered information about past athentications of user, and showing statistics based on that data.
+
+**Input arguments:** ID of searched user
+
+**Result:**
+
+- `HHTP OK [200]` indicating successfull load of show page
diff --git a/config_templates/perun.proxygui.yaml b/config_templates/perun.proxygui.yaml
index cce7329746c3f4b5aa73e670b0c23611ca0b0c1a..71ed2df21482209b4255256d468c0a99920f4d3d 100644
--- a/config_templates/perun.proxygui.yaml
+++ b/config_templates/perun.proxygui.yaml
@@ -124,6 +124,14 @@ consent_database: # REQUIRED
   database_name: database_name
   consent_collection_name: collection_name
   ticket_collection_name: collection_name
+oauth2_provider: # REQUIRED data for a shared Oauth2 configuration for protection of some endpoints
+  issuer: "https://id.muni.cz/"
+  name: provider_name
+  client_id: id
+  client_secret: secret
+  scopes:
+    - openid
+    - perun_consent_api
 jwt_nonce_database: # REQUIRED
   connection_string: connection_string
   database_name: database_name
@@ -140,3 +148,5 @@ oidc_provider: # REQUIRED for OAuth2/OIDC protection of some endpoints
   post_logout_redirect_uris:
     - uri1
     - uri2
+auth_event_logging: # REQUIRED
+  logging_db: postgresql+psycopg2://user:password@hostname/database_name
diff --git a/perun/proxygui/api/heuristic_api.py b/perun/proxygui/api/heuristic_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9789069dddc3d077b9a9f772874f72b8de1618c
--- /dev/null
+++ b/perun/proxygui/api/heuristic_api.py
@@ -0,0 +1,131 @@
+from satosacontrib.perun.utils.AuthEventLoggingDbModels import (
+    AuthEventLoggingTable,
+    UserAgentTable,
+    RequestedAcrsTable,
+)
+from sqlalchemy import create_engine, MetaData, distinct
+from user_agents import parse
+
+
+class AuthEventLoggingQuerries:
+    def __init__(self, cfg):
+        self.logging_db = cfg["auth_event_logging"]["logging_db"]
+
+    def get_last_5_cities(self, user):
+        engine = create_engine(self.logging_db)
+        with engine.connect() as cnxn:
+            meta_data = MetaData(bind=engine)
+            MetaData.reflect(meta_data)
+
+            auth_event_logging = AuthEventLoggingTable().__table__
+            querry = (
+                auth_event_logging.select(
+                    [distinct(auth_event_logging.c.geolocation_city)]
+                )
+                .order_by(auth_event_logging.c.day.desc())
+                .where(auth_event_logging.columns.user == user)
+                .limit(5)
+            )
+            response = cnxn.execute(querry).fetchall()
+
+        result = [r._asdict() for r in response]
+        cities = []
+        for item in result:
+            cities.append(item["geolocation_city"])
+
+        return cities
+
+    def get_last_100_times(self, user):
+        engine = create_engine(self.logging_db)
+        with engine.connect() as cnxn:
+            meta_data = MetaData(bind=engine)
+            MetaData.reflect(meta_data)
+
+            auth_event_logging = AuthEventLoggingTable().__table__
+            querry = (
+                auth_event_logging.select(auth_event_logging.c.day)
+                .order_by(auth_event_logging.c.day.desc())
+                .where(auth_event_logging.c.user == user)
+                .limit(100)
+            )
+            response = cnxn.execute(querry).fetchall()
+
+        result = [r._asdict() for r in response]
+        times = {}
+
+        # Dividing timestamps into dict by half-hours -> {'7:30': 2, '10:00': 1, ...}
+        for item in result:
+            hour = str(item["day"].hour)
+            minutes = item["day"].minute
+            if minutes >= 30:
+                minutes = str(3)
+            else:
+                minutes = str(0)
+
+            if hour + ":" + minutes + "0" not in times:
+                times[hour + ":" + minutes + "0"] = 1
+            else:
+                times[hour + ":" + minutes + "0"] += 1
+
+        return times
+
+    def get_ids_from_foreign_table(self, cnxn, user, auth_table, requested_col, limit):
+        querry = (
+            auth_table.select(requested_col)
+            .where(auth_table.c.user == user)
+            .limit(limit)
+        )
+        return cnxn.execute(querry).fetchall()
+
+    def get_unique_user_agents(self, user):
+        engine = create_engine(self.logging_db)
+        with engine.connect() as cnxn:
+            meta_data = MetaData(bind=engine)
+            MetaData.reflect(meta_data)
+
+            auth_event_logging = AuthEventLoggingTable().__table__
+            user_agent = UserAgentTable().__table__
+
+            ids = self.get_ids_from_foreign_table(
+                cnxn, user, auth_event_logging, auth_event_logging.c.user_agent_id, 200
+            )
+
+            querry = user_agent.select([distinct(user_agent.c.value)]).where(
+                user_agent.c.id in ids
+            )
+            response = cnxn.execute(querry).fetchall()
+        result = [r._asdict() for r in response]
+        agents = []
+
+        for item in result:
+            agents.append(parse(item["value"]))
+
+        return agents
+
+    def get_unique_arcs(self, user):
+        engine = create_engine(self.logging_db)
+        with engine.connect() as cnxn:
+            meta_data = MetaData(bind=engine)
+            MetaData.reflect(meta_data)
+
+            auth_event_logging = AuthEventLoggingTable().__table__
+            req_arcs = RequestedAcrsTable().__table__
+
+            ids = self.get_ids_from_foreign_table(
+                cnxn,
+                user,
+                auth_event_logging,
+                auth_event_logging.c.requested_arcs_id,
+                100,
+            )
+            querry = req_arcs.select([distinct(req_arcs.c.value)]).where(
+                req_arcs.c.id in ids
+            )
+            response = cnxn.execute(querry).fetchall()
+
+        result = [r._asdict() for r in response]
+        arcs = []
+        for item in result:
+            arcs.append(item["value"])
+
+        return arcs
diff --git a/perun/proxygui/app.py b/perun/proxygui/app.py
index ccafe43d7ccb33ed5a4d23fd604b93152bdf442c..35d6afac6734cbe6fb98f39ca686e1e667615f74 100644
--- a/perun/proxygui/app.py
+++ b/perun/proxygui/app.py
@@ -24,6 +24,7 @@ from perun.proxygui.oauth import (
 )
 from perun.utils.CustomRPHandler import CustomRPHandler
 
+
 PROXYGUI_CFG = "perun.proxygui.yaml"
 BACKCHANNEL_LOGOUT_CFG = "backchannel-logout.yaml"
 
@@ -44,6 +45,7 @@ def get_config_path(filename: str, required=True) -> Optional[str]:
 
 def get_config(filename=PROXYGUI_CFG, required=True) -> dict:
     cfg_path = get_config_path(filename, required)
+    print(cfg_path)
     if not cfg_path:
         return {}
     with open(
@@ -134,6 +136,7 @@ def get_flask_app(cfg):
     app.register_blueprint(construct_ban_api_blueprint(cfg))
     app.register_blueprint(construct_kerberos_auth_api_blueprint(cfg))
     # to avoid breaking change
+
     if "consent" in cfg:
         oauth_cfg = cfg["oidc_provider"]
         configure_resource_protector(oauth_cfg)
diff --git a/perun/proxygui/gui/gui.py b/perun/proxygui/gui/gui.py
index 89f8ddd69ad3a1eb917b797f22ed8f08b9687ec9..a93387dc95e1d2d911c8a389c32b53db14d378c5 100644
--- a/perun/proxygui/gui/gui.py
+++ b/perun/proxygui/gui/gui.py
@@ -10,6 +10,7 @@ from flask_pyoidc.user_session import UserSession
 
 from perun.proxygui.jwt import JWTService
 from perun.proxygui.user_manager import UserManager
+from perun.proxygui.api.heuristic_api import AuthEventLoggingQuerries
 from perun.utils.consent_framework.consent_manager import ConsentManager
 
 
@@ -23,11 +24,13 @@ def ignore_claims(ignored_claims, claims):
     return result
 
 
+# def construct_gui_blueprint(cfg, auth):
 def construct_gui_blueprint(cfg, auth):
     gui = Blueprint("gui", __name__, template_folder="templates")
     consent_db_manager = ConsentManager(cfg)
     user_manager = UserManager(cfg)
     jwt_service = JWTService(cfg)
+    auth_event = AuthEventLoggingQuerries(cfg)
 
     REDIRECT_URL = cfg["redirect_url"]
     COLOR = cfg["bootstrap_color"]
@@ -157,4 +160,36 @@ def construct_gui_blueprint(cfg, auth):
             send_mfa_reset_emails=url_for("gui.send_mfa_reset_emails"),
         )
 
+    @auth.oidc_auth(OIDC_CFG["provider_name"])
+    @gui.route("/HeuristicGetID")
+    def heuristic_get_id():
+        return render_template(
+            "HeuristicData.html",
+            redirect_url=REDIRECT_URL,
+            bootstrap_color=COLOR,
+            selected=False,
+        )
+
+    @auth.oidc_auth(OIDC_CFG["provider_name"])
+    @gui.route("/GetHeuristic", methods=["GET"])
+    def get_heuristic():
+        user_id = request.args.get("user")
+        """
+        Database selects from auth_event_logging_microservice
+        e.g.
+        data = get_data(user_id)
+        """
+
+        return render_template(
+            "HeuristicData.html",
+            redirect_url=REDIRECT_URL,
+            bootstrap_color=COLOR,
+            selected=True,
+            user=user_id,
+            last_5_cities=auth_event.get_last_5_cities(user_id),
+            last_100_times=auth_event.get_last_100_times(user_id),
+            user_agents=auth_event.get_unique_user_agents(user_id),
+            arcs=auth_event.get_unique_arcs(user_id),
+        )
+
     return gui
diff --git a/perun/proxygui/gui/templates/HeuristicData.html b/perun/proxygui/gui/templates/HeuristicData.html
new file mode 100644
index 0000000000000000000000000000000000000000..0407eb4b1a9bbf83ba318ddb8db92ce4b47c64ea
--- /dev/null
+++ b/perun/proxygui/gui/templates/HeuristicData.html
@@ -0,0 +1,58 @@
+{% extends 'base.html' %}
+
+{% block contentwrapper %}
+    <div class="window {% if cfg.css_framework == 'MUNI' %}framework_muni{% else %}framework_bootstrap5 bg-light{% endif %}">
+        <div id="content">
+            <div class="wrap{% if not cfg.css_framework == 'MUNI' %} container{% endif %}">
+                {% block content %}
+                    {% if selected %}
+                        <div class="content">
+                            <br/>
+                            <h3><span>{{ _("User ID: ") }}{{ user }}</span></h3>
+                            
+                            <div class="grid">
+                                    <div class="grid__cell size--l--5-12 text-center">
+                                        <h5>Last 5 cities connected from:</h5>
+                                        {% for city in last_5_cities %}
+                                            {{ city }}<br/>
+                                                
+                                         {% endfor %}
+                                    </div>
+                                    <div class="grid__cell size--l--5-12 text-center">
+                                        <h5>Time activity</h5>
+                                        {{ last_100_times }}
+
+                                    </div>
+                            </div>
+                            <div class="grid text-center">
+                                    <div class="grid__cell size--l--5-12 text-center">
+                                        <h5>User agents</h5>
+                                        {% for agent in user_agents %}
+                                            {{ agent }}<br/>
+                                                
+                                        {% endfor %}
+                                    </div>
+                                    <div class="grid__cell size--l--5-12 text-center">
+                                        <h5>Unique requested arcs</h5>
+                                        {% for arc in arcs %}
+                                            {{ arc }}<br/>
+                                                
+                                        {% endfor %}
+                                    </div>
+                            </div>
+                        </div>
+                    {% else %}
+                        <div class="content">
+                            <br/>
+                            <h3><span>{{ _("Specify an ID of user to gather data:") }}</span></h3>
+                            <form action="/GetHeuristic" method="get">
+                                <input type="number" id="userID" name="user" min="1" required>
+                                <input type="submit" value="Submit" name="submit"/>
+                            </form>
+                        </div>
+                    {% endif %}
+                {% endblock %}
+            </div>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
index dde572d97f4427cc11403a6d148f75d95f02652f..ab3941115e93e2024d529fae8109e2b8b9239452 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,4 +1,3 @@
 [metadata]
 version = 3.0.3
 license_files = LICENSE
-
diff --git a/setup.py b/setup.py
index 6b6c89691acb59d9b7dc1b976d9bcbdbba5a69ff..872056c49902f136c45a895321e642be18e0f2ad 100644
--- a/setup.py
+++ b/setup.py
@@ -29,6 +29,8 @@ setup(
         "pymongo~=4.4.1",
         "validators~=0.22.0",
         "idpyoidc~=2.0.0",
+        "satosacontrib.perun~=4.1",
+        "user-agents~=2.2.0",
     ],
     extras_require={
         "kerberos": [