From c18201bfd7bfc6bf5c8d74dbfaa53fad839ec4b4 Mon Sep 17 00:00:00 2001
From: Marko Ivancic <marko.ivancic@srce.hr>
Date: Wed, 8 Mar 2023 15:52:47 +0000
Subject: [PATCH] Enable tracking for OIDC protocol

---
 README.md                                     |   6 +
 composer.json                                 |   2 +-
 composer.lock                                 | 308 +++++++++---------
 hooks/hook_adminmenu.php                      |   6 +-
 hooks/hook_configpage.php                     |   6 +-
 hooks/hook_cron.php                           |  13 +-
 psalm.xml                                     |  16 +-
 src/Auth/Process/Accounting.php               |   5 +-
 src/Entities/Activity.php                     |  22 +-
 src/Entities/Authentication/Event.php         |   7 +-
 .../Authentication/Event/State/Oidc.php       |  91 ++++++
 .../Authentication/Event/State/Saml2.php      |  79 +++++
 src/Entities/Authentication/Protocol/Bag.php  |  32 ++
 src/Entities/Authentication/Protocol/Oidc.php |  23 ++
 .../Authentication/Protocol/Saml2.php         |  21 ++
 src/Entities/Bases/AbstractProvider.php       |  55 +---
 .../State.php => Bases/AbstractState.php}     | 144 +++-----
 src/Entities/ConnectedServiceProvider.php     |  11 +-
 src/Entities/IdentityProvider.php             |  11 -
 .../AuthenticationProtocolInterface.php       |   9 +
 .../Interfaces/IdentityProviderInterface.php  |  12 +
 src/Entities/Interfaces/ProviderInterface.php |  16 +
 .../Interfaces/ServiceProviderInterface.php   |  12 +
 src/Entities/Interfaces/StateInterface.php    |  22 ++
 src/Entities/Providers/Identity/Oidc.php      |  39 +++
 src/Entities/Providers/Identity/Saml2.php     |  41 +++
 src/Entities/Providers/Service/Oidc.php       |  41 +++
 src/Entities/Providers/Service/Saml2.php      |  41 +++
 src/Entities/ServiceProvider.php              |  11 -
 src/Exceptions/MetadataException.php          |  11 +
 src/Exceptions/StateException.php             |  11 +
 src/Helpers/{ArrayHelper.php => Arr.php}      |   2 +-
 .../{AttributesHelper.php => Attributes.php}  |   4 +-
 .../AuthenticationEventStateResolver.php      |  53 +++
 .../{DateTimeHelper.php => DateTime.php}      |   2 +-
 ...{EnvironmentHelper.php => Environment.php} |   2 +-
 .../{FilesystemHelper.php => Filesystem.php}  |   2 +-
 src/Helpers/{HashHelper.php => Hash.php}      |   6 +-
 ...stanceBuilderUsingModuleConfiguration.php} |   6 +-
 ...oduleRoutesHelper.php => ModuleRoutes.php} |   7 +-
 .../{NetworkHelper.php => Network.php}        |   2 +-
 src/Helpers/ProviderResolver.php              |  54 +++
 src/Helpers/{RandomHelper.php => Random.php}  |   2 +-
 src/Http/Controllers/Admin/Configuration.php  |   9 +-
 src/Http/Controllers/User/Profile.php         |  15 +-
 ...dableUsingModuleConfigurationInterface.php |   2 -
 src/ModuleConfiguration.php                   |   8 -
 .../AuthenticationDataProviderBuilder.php     |   2 +-
 src/Services/HelpersManager.php               |  97 +++---
 src/Services/JobRunner.php                    |  10 +-
 src/Services/JobRunner/RateLimiter.php        |   4 +-
 .../Bases/DoctrineDbal/AbstractRawEntity.php  |   3 +
 .../Builders/Bases/AbstractStoreBuilder.php   |   2 +-
 .../Connections/Bases/AbstractMigrator.php    |   2 +-
 .../DoctrineDbal/Versioned/Store.php          |  19 +-
 .../Versioned/Store/HashDecoratedState.php    |  21 +-
 ...01000700CreateAuthenticationEventTable.php |   4 +
 .../Versioned/Store/RawActivity.php           |  14 +
 .../Versioned/Store/Repository.php            |  32 +-
 .../Versioned/Store/TableConstants.php        |   5 +
 .../Jobs/DoctrineDbal/Store/Repository.php    |   4 +
 src/Stores/Jobs/PhpRedis/RedisStore.php       |   3 +
 .../DoctrineDbal/Versioned/Tracker.php        |   4 +-
 .../AuthenticationDataTrackerBuilder.php      |   2 +-
 templates/user/activity.twig                  |  11 +-
 templates/user/connected-organizations.twig   |   9 -
 tests/src/Auth/Process/AccountingTest.php     |  29 +-
 tests/src/Constants/RawRowResult.php          |   1 +
 tests/src/Constants/StateArrays.php           | 106 +++++-
 tests/src/Entities/Activity/BagTest.php       |   1 -
 tests/src/Entities/ActivityTest.php           |  14 +-
 .../Entities/Authentication/Event/JobTest.php |  11 +-
 .../Authentication/Event/State/OidcTest.php   | 145 +++++++++
 .../State/Saml2Test.php}                      | 106 +++---
 .../src/Entities/Authentication/EventTest.php |  13 +-
 .../Authentication/Protocol/BagTest.php       |  41 +++
 .../Authentication/Protocol/OidcTest.php      |  25 ++
 .../Authentication/Protocol/Saml2Test.php     |  24 ++
 .../Entities/Bases/AbstractProviderTest.php   |  72 ++--
 .../src/Entities/Bases/AbstractStateTest.php  | 200 ++++++++++++
 .../Entities/ConnectedServiceProviderTest.php |   9 +-
 tests/src/Entities/IdentityProviderTest.php   |  34 --
 .../Entities/Providers/Identity/OidcTest.php  |  47 +++
 .../Entities/Providers/Identity/Saml2Test.php |  49 +++
 .../Entities/Providers/Service/OidcTest.php   |  49 +++
 .../Entities/Providers/Service/Saml2Test.php  |  44 +++
 tests/src/Entities/ServiceProviderTest.php    |  33 --
 .../{ArrayHelperTest.php => ArrayTest.php}    |   8 +-
 ...butesHelperTest.php => AttributesTest.php} |   8 +-
 .../AuthenticationEventStateResolverTest.php  |  56 ++++
 ...ateTimeHelperTest.php => DateTimeTest.php} |  10 +-
 tests/src/Helpers/EnvironmentHelperTest.php   |  19 --
 tests/src/Helpers/EnvironmentTest.php         |  19 ++
 ...ystemHelperTest.php => FilesystemTest.php} |  10 +-
 .../{HashHelperTest.php => HashTest.php}      |  14 +-
 ...ceBuilderUsingModuleConfigurationTest.php} |  12 +-
 ...tesHelperTest.php => ModuleRoutesTest.php} |  17 +-
 tests/src/Helpers/NetworkHelperTest.php       |  48 ---
 tests/src/Helpers/NetworkTest.php             |  60 ++++
 tests/src/Helpers/ProviderResolverTest.php    |  74 +++++
 tests/src/Helpers/RandomHelperTest.php        |  19 --
 tests/src/Helpers/RandomTest.php              |  19 ++
 tests/src/ModuleConfigurationTest.php         |   6 +-
 .../AuthenticationDataProviderBuilderTest.php |   5 +-
 tests/src/Services/HelpersManagerTest.php     |  53 +--
 .../Services/JobRunner/RateLimiterTest.php    |   2 +-
 tests/src/Services/JobRunnerTest.php          | 110 +++----
 tests/src/Stores/Bases/AbstractStoreTest.php  |   5 +-
 .../DoctrineDbal/AbstractRawEntityTest.php    |   3 -
 .../Stores/Builders/DataStoreBuilderTest.php  |   3 +-
 .../Stores/Builders/JobsStoreBuilderTest.php  |   7 +-
 .../Bases/AbstractMigratorTest.php            |   9 +-
 .../Connections/DoctrineDbal/FactoryTest.php  |   2 -
 .../Connections/DoctrineDbal/MigratorTest.php |  12 +-
 .../Store/HashDecoratedStateTest.php          |  12 +-
 ...ersion20220801000000CreateIdpTableTest.php |   3 -
 ...0220801000100CreateIdpVersionTableTest.php |   3 -
 ...Version20220801000200CreateSpTableTest.php |   3 -
 ...20220801000300CreateSpVersionTableTest.php |   3 -
 ...rsion20220801000400CreateUserTableTest.php |   3 -
 ...220801000500CreateUserVersionTableTest.php |   3 -
 ...1000600CreateIdpSpUserVersionTableTest.php |   3 -
 ...0700CreateAuthenticationEventTableTest.php |   3 -
 .../Versioned/Store/RawActivityTest.php       |  31 +-
 .../Store/RawConnectedServiceProviderTest.php |  10 -
 .../Versioned/Store/RepositoryTest.php        |  22 +-
 .../DoctrineDbal/Versioned/StoreTest.php      |  66 ++--
 .../Jobs/DoctrineDbal/Store/RawJobTest.php    |  16 +-
 .../DoctrineDbal/Store/RepositoryTest.php     |  28 +-
 .../Stores/Jobs/DoctrineDbal/StoreTest.php    |  37 +--
 .../Stores/Jobs/PhpRedis/RedisStoreTest.php   |  59 +---
 .../DoctrineDbal/Versioned/TrackerTest.php    |  19 +-
 .../AuthenticationDataTrackerBuilderTest.php  |   8 +-
 133 files changed, 2406 insertions(+), 1137 deletions(-)
 create mode 100644 src/Entities/Authentication/Event/State/Oidc.php
 create mode 100644 src/Entities/Authentication/Event/State/Saml2.php
 create mode 100644 src/Entities/Authentication/Protocol/Bag.php
 create mode 100644 src/Entities/Authentication/Protocol/Oidc.php
 create mode 100644 src/Entities/Authentication/Protocol/Saml2.php
 rename src/Entities/{Authentication/State.php => Bases/AbstractState.php} (59%)
 delete mode 100644 src/Entities/IdentityProvider.php
 create mode 100644 src/Entities/Interfaces/AuthenticationProtocolInterface.php
 create mode 100644 src/Entities/Interfaces/IdentityProviderInterface.php
 create mode 100644 src/Entities/Interfaces/ProviderInterface.php
 create mode 100644 src/Entities/Interfaces/ServiceProviderInterface.php
 create mode 100644 src/Entities/Interfaces/StateInterface.php
 create mode 100644 src/Entities/Providers/Identity/Oidc.php
 create mode 100644 src/Entities/Providers/Identity/Saml2.php
 create mode 100644 src/Entities/Providers/Service/Oidc.php
 create mode 100644 src/Entities/Providers/Service/Saml2.php
 delete mode 100644 src/Entities/ServiceProvider.php
 create mode 100644 src/Exceptions/MetadataException.php
 create mode 100644 src/Exceptions/StateException.php
 rename src/Helpers/{ArrayHelper.php => Arr.php} (95%)
 rename src/Helpers/{AttributesHelper.php => Attributes.php} (88%)
 create mode 100644 src/Helpers/AuthenticationEventStateResolver.php
 rename src/Helpers/{DateTimeHelper.php => DateTime.php} (96%)
 rename src/Helpers/{EnvironmentHelper.php => Environment.php} (88%)
 rename src/Helpers/{FilesystemHelper.php => Filesystem.php} (95%)
 rename src/Helpers/{HashHelper.php => Hash.php} (78%)
 rename src/Helpers/{InstanceBuilderUsingModuleConfigurationHelper.php => InstanceBuilderUsingModuleConfiguration.php} (94%)
 rename src/Helpers/{ModuleRoutesHelper.php => ModuleRoutes.php} (78%)
 rename src/Helpers/{NetworkHelper.php => Network.php} (97%)
 create mode 100644 src/Helpers/ProviderResolver.php
 rename src/Helpers/{RandomHelper.php => Random.php} (95%)
 create mode 100644 tests/src/Entities/Authentication/Event/State/OidcTest.php
 rename tests/src/Entities/Authentication/{StateTest.php => Event/State/Saml2Test.php} (60%)
 create mode 100644 tests/src/Entities/Authentication/Protocol/BagTest.php
 create mode 100644 tests/src/Entities/Authentication/Protocol/OidcTest.php
 create mode 100644 tests/src/Entities/Authentication/Protocol/Saml2Test.php
 create mode 100644 tests/src/Entities/Bases/AbstractStateTest.php
 delete mode 100644 tests/src/Entities/IdentityProviderTest.php
 create mode 100644 tests/src/Entities/Providers/Identity/OidcTest.php
 create mode 100644 tests/src/Entities/Providers/Identity/Saml2Test.php
 create mode 100644 tests/src/Entities/Providers/Service/OidcTest.php
 create mode 100644 tests/src/Entities/Providers/Service/Saml2Test.php
 delete mode 100644 tests/src/Entities/ServiceProviderTest.php
 rename tests/src/Helpers/{ArrayHelperTest.php => ArrayTest.php} (70%)
 rename tests/src/Helpers/{AttributesHelperTest.php => AttributesTest.php} (92%)
 create mode 100644 tests/src/Helpers/AuthenticationEventStateResolverTest.php
 rename tests/src/Helpers/{DateTimeHelperTest.php => DateTimeTest.php} (55%)
 delete mode 100644 tests/src/Helpers/EnvironmentHelperTest.php
 create mode 100644 tests/src/Helpers/EnvironmentTest.php
 rename tests/src/Helpers/{FilesystemHelperTest.php => FilesystemTest.php} (66%)
 rename tests/src/Helpers/{HashHelperTest.php => HashTest.php} (82%)
 rename tests/src/Helpers/{InstanceBuilderUsingModuleConfigurationHelperTest.php => InstanceBuilderUsingModuleConfigurationTest.php} (84%)
 rename tests/src/Helpers/{ModuleRoutesHelperTest.php => ModuleRoutesTest.php} (70%)
 delete mode 100644 tests/src/Helpers/NetworkHelperTest.php
 create mode 100644 tests/src/Helpers/NetworkTest.php
 create mode 100644 tests/src/Helpers/ProviderResolverTest.php
 delete mode 100644 tests/src/Helpers/RandomHelperTest.php
 create mode 100644 tests/src/Helpers/RandomTest.php

diff --git a/README.md b/README.md
index c37884d..7061c71 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,11 @@
 [![Test](https://github.com/cicnavi/simplesamlphp-module-accounting/actions/workflows/test.yml/badge.svg)](https://github.com/cicnavi/simplesamlphp-module-accounting/actions/workflows/test.yml)
 
+
+* TODO 
+* Consider config to enable / disable storing attribute values
+* IG Binary - consider using for data serialization
+
+
 # simplesamlphp-module-accounting
 SimpleSAMLphp module providing user accounting functionality using SimpleSAMLphp authentication processing 
 filters feature.
diff --git a/composer.json b/composer.json
index c7e7ffa..4c2e7fc 100644
--- a/composer.json
+++ b/composer.json
@@ -34,7 +34,7 @@
         "cicnavi/simple-file-cache-php": "^2.0"
     },
     "require-dev": {
-        "vimeo/psalm": "^4",
+        "vimeo/psalm": "^5",
         "phpunit/phpunit": "^9",
         "squizlabs/php_codesniffer": "^3",
         "simplesamlphp/simplesamlphp": "^2@beta",
diff --git a/composer.lock b/composer.lock
index b3cf7bb..64d9ba6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "e1bdcb1340cc34e659c651695992a6b8",
+    "content-hash": "fe21f8863239731b2f1746d3e887dff7",
     "packages": [
         {
             "name": "cicnavi/simple-file-cache-php",
@@ -1782,6 +1782,67 @@
             },
             "time": "2022-03-02T22:36:06+00:00"
         },
+        {
+            "name": "fidry/cpu-core-counter",
+            "version": "0.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/theofidry/cpu-core-counter.git",
+                "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623",
+                "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "fidry/makefile": "^0.2.0",
+                "phpstan/extension-installer": "^1.2.0",
+                "phpstan/phpstan": "^1.9.2",
+                "phpstan/phpstan-deprecation-rules": "^1.0.0",
+                "phpstan/phpstan-phpunit": "^1.2.2",
+                "phpstan/phpstan-strict-rules": "^1.4.4",
+                "phpunit/phpunit": "^9.5.26 || ^8.5.31",
+                "theofidry/php-cs-fixer-config": "^1.0",
+                "webmozarts/strict-phpunit": "^7.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Fidry\\CpuCoreCounter\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Théo FIDRY",
+                    "email": "theo.fidry@gmail.com"
+                }
+            ],
+            "description": "Tiny utility to get the number of CPU cores.",
+            "keywords": [
+                "CPU",
+                "core"
+            ],
+            "support": {
+                "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+                "source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/theofidry",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-12-24T12:35:10+00:00"
+        },
         {
             "name": "gettext/gettext",
             "version": "v5.7.0",
@@ -2240,59 +2301,6 @@
             },
             "time": "2023-01-16T22:05:37+00:00"
         },
-        {
-            "name": "openlss/lib-array2xml",
-            "version": "1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/nullivex/lib-array2xml.git",
-                "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
-                "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.2"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-0": {
-                    "LSS": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "Apache-2.0"
-            ],
-            "authors": [
-                {
-                    "name": "Bryan Tong",
-                    "email": "bryan@nullivex.com",
-                    "homepage": "https://www.nullivex.com"
-                },
-                {
-                    "name": "Tony Butler",
-                    "email": "spudz76@gmail.com",
-                    "homepage": "https://www.nullivex.com"
-                }
-            ],
-            "description": "Array2XML conversion library credit to lalit.org",
-            "homepage": "https://www.nullivex.com",
-            "keywords": [
-                "array",
-                "array conversion",
-                "xml",
-                "xml conversion"
-            ],
-            "support": {
-                "issues": "https://github.com/nullivex/lib-array2xml/issues",
-                "source": "https://github.com/nullivex/lib-array2xml/tree/master"
-            },
-            "time": "2019-03-29T20:06:56+00:00"
-        },
         {
             "name": "phar-io/manifest",
             "version": "2.0.3",
@@ -4600,16 +4608,16 @@
         },
         {
             "name": "simplesamlphp/simplesamlphp-assets-base",
-            "version": "v2.0.2",
+            "version": "v2.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/simplesamlphp/simplesamlphp-assets-base.git",
-                "reference": "23d8bd528a13284f48070114fa20934cb826c644"
+                "reference": "dcc7c7e485a6e6f03e6b2ff7abf64a2149a2fdd0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-assets-base/zipball/23d8bd528a13284f48070114fa20934cb826c644",
-                "reference": "23d8bd528a13284f48070114fa20934cb826c644",
+                "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-assets-base/zipball/dcc7c7e485a6e6f03e6b2ff7abf64a2149a2fdd0",
+                "reference": "dcc7c7e485a6e6f03e6b2ff7abf64a2149a2fdd0",
                 "shasum": ""
             },
             "require": {
@@ -4630,9 +4638,9 @@
             "description": "Assets for the SimpleSAMLphp main repository",
             "support": {
                 "issues": "https://github.com/simplesamlphp/simplesamlphp-assets-base/issues",
-                "source": "https://github.com/simplesamlphp/simplesamlphp-assets-base/tree/v2.0.2"
+                "source": "https://github.com/simplesamlphp/simplesamlphp-assets-base/tree/v2.0.3"
             },
-            "time": "2023-01-27T18:20:32+00:00"
+            "time": "2023-02-22T12:34:35+00:00"
         },
         {
             "name": "simplesamlphp/simplesamlphp-test-framework",
@@ -4691,6 +4699,70 @@
             },
             "time": "2023-01-12T16:20:27+00:00"
         },
+        {
+            "name": "spatie/array-to-xml",
+            "version": "2.17.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/array-to-xml.git",
+                "reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/5cbec9c6ab17e320c58a259f0cebe88bde4a7c46",
+                "reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "php": "^7.4|^8.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "^1.2",
+                "pestphp/pest": "^1.21",
+                "phpunit/phpunit": "^9.0",
+                "spatie/pest-plugin-snapshots": "^1.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\ArrayToXml\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://freek.dev",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Convert an array to xml",
+            "homepage": "https://github.com/spatie/array-to-xml",
+            "keywords": [
+                "array",
+                "convert",
+                "xml"
+            ],
+            "support": {
+                "source": "https://github.com/spatie/array-to-xml/tree/2.17.1"
+            },
+            "funding": [
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-12-26T08:22:07+00:00"
+        },
         {
             "name": "squizlabs/php_codesniffer",
             "version": "3.7.1",
@@ -7654,24 +7726,24 @@
         },
         {
             "name": "vimeo/psalm",
-            "version": "4.30.0",
+            "version": "5.7.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/vimeo/psalm.git",
-                "reference": "d0bc6e25d89f649e4f36a534f330f8bb4643dd69"
+                "reference": "5390c212bab06ee230c8720c2e9c54b823db00c8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/vimeo/psalm/zipball/d0bc6e25d89f649e4f36a534f330f8bb4643dd69",
-                "reference": "d0bc6e25d89f649e4f36a534f330f8bb4643dd69",
+                "url": "https://api.github.com/repos/vimeo/psalm/zipball/5390c212bab06ee230c8720c2e9c54b823db00c8",
+                "reference": "5390c212bab06ee230c8720c2e9c54b823db00c8",
                 "shasum": ""
             },
             "require": {
                 "amphp/amp": "^2.4.2",
                 "amphp/byte-stream": "^1.5",
-                "composer/package-versions-deprecated": "^1.8.0",
+                "composer/package-versions-deprecated": "^1.10.0",
                 "composer/semver": "^1.4 || ^2.0 || ^3.0",
-                "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0",
+                "composer/xdebug-handler": "^2.0 || ^3.0",
                 "dnoegel/php-xdg-base-dir": "^0.1.1",
                 "ext-ctype": "*",
                 "ext-dom": "*",
@@ -7680,35 +7752,34 @@
                 "ext-mbstring": "*",
                 "ext-simplexml": "*",
                 "ext-tokenizer": "*",
-                "felixfbecker/advanced-json-rpc": "^3.0.3",
-                "felixfbecker/language-server-protocol": "^1.5",
+                "felixfbecker/advanced-json-rpc": "^3.1",
+                "felixfbecker/language-server-protocol": "^1.5.2",
+                "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1",
                 "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
                 "nikic/php-parser": "^4.13",
-                "openlss/lib-array2xml": "^1.0",
-                "php": "^7.1|^8",
-                "sebastian/diff": "^3.0 || ^4.0",
-                "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0",
-                "symfony/polyfill-php80": "^1.25",
-                "webmozart/path-util": "^2.3"
+                "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0",
+                "sebastian/diff": "^4.0 || ^5.0",
+                "spatie/array-to-xml": "^2.17.0 || ^3.0",
+                "symfony/console": "^4.1.6 || ^5.0 || ^6.0",
+                "symfony/filesystem": "^5.4 || ^6.0"
             },
             "provide": {
                 "psalm/psalm": "self.version"
             },
             "require-dev": {
-                "bamarni/composer-bin-plugin": "^1.2",
-                "brianium/paratest": "^4.0||^6.0",
+                "bamarni/composer-bin-plugin": "^1.4",
+                "brianium/paratest": "^6.9",
                 "ext-curl": "*",
+                "mockery/mockery": "^1.5",
+                "nunomaduro/mock-final-classes": "^1.1",
                 "php-parallel-lint/php-parallel-lint": "^1.2",
-                "phpdocumentor/reflection-docblock": "^5",
-                "phpmyadmin/sql-parser": "5.1.0||dev-master",
-                "phpspec/prophecy": ">=1.9.0",
-                "phpstan/phpdoc-parser": "1.2.* || 1.6.4",
-                "phpunit/phpunit": "^9.0",
-                "psalm/plugin-phpunit": "^0.16",
-                "slevomat/coding-standard": "^7.0",
-                "squizlabs/php_codesniffer": "^3.5",
-                "symfony/process": "^4.3 || ^5.0 || ^6.0",
-                "weirdan/prophecy-shim": "^1.0 || ^2.0"
+                "phpstan/phpdoc-parser": "^1.6",
+                "phpunit/phpunit": "^9.6",
+                "psalm/plugin-mockery": "^1.1",
+                "psalm/plugin-phpunit": "^0.18",
+                "slevomat/coding-standard": "^8.4",
+                "squizlabs/php_codesniffer": "^3.6",
+                "symfony/process": "^4.4 || ^5.0 || ^6.0"
             },
             "suggest": {
                 "ext-curl": "In order to send data to shepherd",
@@ -7724,17 +7795,14 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.x-dev",
+                    "dev-master": "5.x-dev",
+                    "dev-4.x": "4.x-dev",
                     "dev-3.x": "3.x-dev",
                     "dev-2.x": "2.x-dev",
                     "dev-1.x": "1.x-dev"
                 }
             },
             "autoload": {
-                "files": [
-                    "src/functions.php",
-                    "src/spl_object_id.php"
-                ],
                 "psr-4": {
                     "Psalm\\": "src/Psalm/"
                 }
@@ -7752,64 +7820,14 @@
             "keywords": [
                 "code",
                 "inspection",
-                "php"
+                "php",
+                "static analysis"
             ],
             "support": {
                 "issues": "https://github.com/vimeo/psalm/issues",
-                "source": "https://github.com/vimeo/psalm/tree/4.30.0"
-            },
-            "time": "2022-11-06T20:37:08+00:00"
-        },
-        {
-            "name": "webmozart/path-util",
-            "version": "2.3.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/webmozart/path-util.git",
-                "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725",
-                "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "webmozart/assert": "~1.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6",
-                "sebastian/version": "^1.0.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.3-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Webmozart\\PathUtil\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@gmail.com"
-                }
-            ],
-            "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.",
-            "support": {
-                "issues": "https://github.com/webmozart/path-util/issues",
-                "source": "https://github.com/webmozart/path-util/tree/2.3.0"
+                "source": "https://github.com/vimeo/psalm/tree/5.7.5"
             },
-            "abandoned": "symfony/filesystem",
-            "time": "2015-12-17T08:42:14+00:00"
+            "time": "2023-02-21T16:02:51+00:00"
         }
     ],
     "aliases": [],
diff --git a/hooks/hook_adminmenu.php b/hooks/hook_adminmenu.php
index 9d7c996..1df9352 100644
--- a/hooks/hook_adminmenu.php
+++ b/hooks/hook_adminmenu.php
@@ -3,7 +3,7 @@
 declare(strict_types=1);
 
 use SimpleSAML\Locale\Translate;
-use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\XHTML\Template;
 
@@ -12,11 +12,11 @@ function accounting_hook_adminmenu(Template &$template): void
 {
     $menuKey = 'menu';
 
-    $moduleRoutesHelper = new ModuleRoutesHelper();
+    $moduleRoutesHelper = new ModuleRoutes();
 
     $profilePageEntry = [
         ModuleConfiguration::MODULE_NAME => [
-            'url' => $moduleRoutesHelper->getUrl(ModuleRoutesHelper::PATH_USER_PERSONAL_DATA),
+            'url' => $moduleRoutesHelper->getUrl(ModuleRoutes::PATH_USER_PERSONAL_DATA),
             'name' => Translate::noop('Profile Page'),
         ],
     ];
diff --git a/hooks/hook_configpage.php b/hooks/hook_configpage.php
index c950bbc..93edf93 100644
--- a/hooks/hook_configpage.php
+++ b/hooks/hook_configpage.php
@@ -3,14 +3,14 @@
 declare(strict_types=1);
 
 use SimpleSAML\Locale\Translate;
-use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\XHTML\Template;
 
 /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection Reference is used by SimpleSAMLphp */
 function accounting_hook_configpage(Template &$template): void
 {
-    $moduleRoutesHelper = new ModuleRoutesHelper();
+    $moduleRoutesHelper = new ModuleRoutes();
 
     $dataLinksKey = 'links';
 
@@ -19,7 +19,7 @@ function accounting_hook_configpage(Template &$template): void
     }
 
     $template->data[$dataLinksKey][] = [
-        'href' => $moduleRoutesHelper->getUrl(ModuleRoutesHelper::PATH_ADMIN_CONFIGURATION_STATUS),
+        'href' => $moduleRoutesHelper->getUrl(ModuleRoutes::PATH_ADMIN_CONFIGURATION_STATUS),
         'text' => Translate::noop('Accounting configuration status'),
     ];
 
diff --git a/hooks/hook_cron.php b/hooks/hook_cron.php
index 0bd374c..faf0f65 100644
--- a/hooks/hook_cron.php
+++ b/hooks/hook_cron.php
@@ -10,6 +10,10 @@ use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Module\accounting\Services\Logger;
 use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
 
+/**
+ * @param array $cronInfo
+ * @return void
+ */
 function accounting_hook_cron(array &$cronInfo): void
 {
     $moduleConfiguration = new ModuleConfiguration();
@@ -18,7 +22,7 @@ function accounting_hook_cron(array &$cronInfo): void
     /** @var ?string $currentCronTag */
     $currentCronTag = $cronInfo['tag'] ?? null;
 
-    if (!isset($cronInfo['summary']) || !is_array($cronInfo['summary'])) {
+    if (!is_array($cronInfo['summary'])) {
         $cronInfo['summary'] = [];
     }
 
@@ -42,13 +46,10 @@ function accounting_hook_cron(array &$cronInfo): void
         }
     } catch (Throwable $exception) {
         $message = 'Job runner error: ' . $exception->getMessage();
+        /** @psalm-suppress MixedArrayAssignment */
         $cronInfo['summary'][] = $message;
     }
 
-    if (!isset($cronInfo['summary']) || !is_array($cronInfo['summary'])) {
-        $cronInfo['summary'] = [];
-    }
-
     /**
      * Tracker data retention policy handling.
      */
@@ -61,11 +62,13 @@ function accounting_hook_cron(array &$cronInfo): void
             $helpersManager = new HelpersManager();
             $message = sprintf('Handling data retention policy.');
             $logger->info($message);
+            /** @psalm-suppress MixedArrayAssignment */
             $cronInfo['summary'][] = $message;
             handleDataRetentionPolicy($moduleConfiguration, $logger, $helpersManager, $retentionPolicy);
         }
     } catch (Throwable $exception) {
         $message = 'Error enforcing tracker data retention policy: ' . $exception->getMessage();
+        /** @psalm-suppress MixedArrayAssignment */
         $cronInfo['summary'][] = $message;
     }
 }
diff --git a/psalm.xml b/psalm.xml
index aac60c5..618c01a 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -2,6 +2,8 @@
 <psalm
     errorLevel="1"
     resolveFromConfigFile="true"
+    findUnusedBaselineEntry="true"
+    findUnusedCode="true"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="https://getpsalm.org/schema/config"
     xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
@@ -9,7 +11,6 @@
     <projectFiles>
         <directory name="src" />
         <directory name="config-templates" />
-        <directory name="tests" />
         <directory name="public" />
         <directory name="hooks" />
 
@@ -28,14 +29,9 @@
             </errorLevel>
         </UnusedVariable>
 
-        <!--
-        Ignore PropertyNotSetInConstructor for phpunit tests. For example, this will ignore things like
-        "Property SomeTestClass::$backupStaticAttributes is not defined in constructor of SomeTestClass..."
-        -->
-        <PropertyNotSetInConstructor>
-            <errorLevel type="suppress">
-                <directory name="tests" />
-            </errorLevel>
-        </PropertyNotSetInConstructor>
+        <!-- Ignore errors related to unused classes, methods... -->
+        <UnusedClass errorLevel="suppress" />
+        <PossiblyUnusedMethod errorLevel="suppress" />
+        <PossiblyUnusedReturnValue errorLevel="suppress" />
     </issueHandlers>
 </psalm>
diff --git a/src/Auth/Process/Accounting.php b/src/Auth/Process/Accounting.php
index b84d3a2..ecb6102 100644
--- a/src/Auth/Process/Accounting.php
+++ b/src/Auth/Process/Accounting.php
@@ -7,7 +7,6 @@ namespace SimpleSAML\Module\accounting\Auth\Process;
 use Psr\Log\LoggerInterface;
 use SimpleSAML\Auth\ProcessingFilter;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
 use SimpleSAML\Module\accounting\Exceptions\StoreException;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
@@ -60,7 +59,9 @@ class Accounting extends ProcessingFilter
     public function process(array &$state): void
     {
         try {
-            $authenticationEvent = new Event(new State($state));
+            $resolvedState = $this->helpersManager->getAuthenticationEventStateResolver()->fromStateArray($state);
+
+            $authenticationEvent = new Event($resolvedState);
 
             if ($this->isAccountingProcessingTypeAsynchronous()) {
                 // Only create authentication event job for later processing...
diff --git a/src/Entities/Activity.php b/src/Entities/Activity.php
index 7371efd..a57b667 100644
--- a/src/Entities/Activity.php
+++ b/src/Entities/Activity.php
@@ -5,30 +5,34 @@ declare(strict_types=1);
 namespace SimpleSAML\Module\accounting\Entities;
 
 use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
 
 class Activity
 {
-    protected ServiceProvider $serviceProvider;
+    protected ServiceProviderInterface $serviceProvider;
     protected User $user;
     protected DateTimeImmutable $happenedAt;
     protected ?string $clientIpAddress;
+    protected ?string $authenticationProtocolDesignation;
 
     public function __construct(
-        ServiceProvider $serviceProvider,
+        ServiceProviderInterface $serviceProvider,
         User $user,
         DateTimeImmutable $happenedAt,
-        ?string $clientIpAddress
+        ?string $clientIpAddress,
+        ?string $authenticationProtocolDesignation
     ) {
         $this->serviceProvider = $serviceProvider;
         $this->user = $user;
         $this->happenedAt = $happenedAt;
         $this->clientIpAddress = $clientIpAddress;
+        $this->authenticationProtocolDesignation = $authenticationProtocolDesignation;
     }
 
     /**
-     * @return ServiceProvider
+     * @return ServiceProviderInterface
      */
-    public function getServiceProvider(): ServiceProvider
+    public function getServiceProvider(): ServiceProviderInterface
     {
         return $this->serviceProvider;
     }
@@ -56,4 +60,12 @@ class Activity
     {
         return $this->clientIpAddress;
     }
+
+    /**
+     * @return string|null
+     */
+    public function getAuthenticationProtocolDesignation(): ?string
+    {
+        return $this->authenticationProtocolDesignation;
+    }
 }
diff --git a/src/Entities/Authentication/Event.php b/src/Entities/Authentication/Event.php
index 3155d2e..a72019c 100644
--- a/src/Entities/Authentication/Event.php
+++ b/src/Entities/Authentication/Event.php
@@ -6,19 +6,20 @@ namespace SimpleSAML\Module\accounting\Entities\Authentication;
 
 use DateTimeImmutable;
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Entities\Interfaces\StateInterface;
 
 class Event extends AbstractPayload
 {
-    protected State $state;
+    protected StateInterface $state;
     protected DateTimeImmutable $happenedAt;
 
-    public function __construct(State $state, DateTimeImmutable $happenedAt = null)
+    public function __construct(StateInterface $state, DateTimeImmutable $happenedAt = null)
     {
         $this->state = $state;
         $this->happenedAt = $happenedAt ?? new DateTimeImmutable();
     }
 
-    public function getState(): State
+    public function getState(): StateInterface
     {
         return $this->state;
     }
diff --git a/src/Entities/Authentication/Event/State/Oidc.php b/src/Entities/Authentication/Event/State/Oidc.php
new file mode 100644
index 0000000..b9c384f
--- /dev/null
+++ b/src/Entities/Authentication/Event/State/Oidc.php
@@ -0,0 +1,91 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity;
+use SimpleSAML\Module\accounting\Entities\Providers\Service;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractState;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+
+class Oidc extends AbstractState
+{
+    public const KEY_OIDC = 'Oidc';
+
+    public const KEY_OPEN_ID_PROVIDER_METADATA = 'OpenIdProviderMetadata';
+
+    public const KEY_RELYING_PARTY_METADATA = 'RelyingPartyMetadata';
+
+    protected function resolveIdentityProviderMetadata(array $state): array
+    {
+        $oidcState = $this->extractOidcPart($state);
+
+        if (
+            !empty($oidcState[self::KEY_OPEN_ID_PROVIDER_METADATA]) &&
+            is_array($oidcState[self::KEY_OPEN_ID_PROVIDER_METADATA])
+        ) {
+            return $oidcState[self::KEY_OPEN_ID_PROVIDER_METADATA];
+        }
+
+        throw new UnexpectedValueException('State array does not contain OpenID Provider metadata.');
+    }
+
+    protected function resolveIdentityProviderEntityId(): string
+    {
+        if (
+            !empty($this->identityProviderMetadata[Identity\Oidc::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->identityProviderMetadata[Identity\Oidc::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->identityProviderMetadata[Identity\Oidc::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('OpenID Provider metadata array does not contain issuer.');
+    }
+
+    protected function resolveServiceProviderMetadata(array $state): array
+    {
+        $oidcState = $this->extractOidcPart($state);
+
+        if (
+            !empty($oidcState[self::KEY_RELYING_PARTY_METADATA]) &&
+            is_array($oidcState[self::KEY_RELYING_PARTY_METADATA])
+        ) {
+            return $oidcState[self::KEY_RELYING_PARTY_METADATA];
+        }
+
+        throw new UnexpectedValueException('State array does not contain Relying Party metadata.');
+    }
+
+    protected function resolveServiceProviderEntityId(): string
+    {
+        if (
+            !empty($this->serviceProviderMetadata[Service\Oidc::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->serviceProviderMetadata[Service\Oidc::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->serviceProviderMetadata[Service\Oidc::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('Relying Party metadata array does not contain entity ID.');
+    }
+
+    public function getAuthenticationProtocol(): AuthenticationProtocolInterface
+    {
+        return new Protocol\Oidc();
+    }
+
+    protected function extractOidcPart(array $state): array
+    {
+        if (
+            !empty($state[self::KEY_OIDC]) &&
+            is_array($state[self::KEY_OIDC])
+        ) {
+            return $state[self::KEY_OIDC];
+        }
+
+        throw new UnexpectedValueException('State array does not contain OpenID Connect protocol metadata.');
+    }
+}
diff --git a/src/Entities/Authentication/Event/State/Saml2.php b/src/Entities/Authentication/Event/State/Saml2.php
new file mode 100644
index 0000000..4909033
--- /dev/null
+++ b/src/Entities/Authentication/Event/State/Saml2.php
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractState;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity;
+use SimpleSAML\Module\accounting\Entities\Providers\Service;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+
+use function sprintf;
+
+class Saml2 extends AbstractState
+{
+    public const KEY_IDENTITY_PROVIDER_METADATA = 'IdPMetadata';
+    public const KEY_SOURCE = 'Source';
+    public const KEY_SERVICE_PROVIDER_METADATA = 'SPMetadata';
+    public const KEY_DESTINATION = 'Destination';
+
+    protected function resolveIdentityProviderMetadata(array $state): array
+    {
+        if (
+            !empty($state[self::KEY_IDENTITY_PROVIDER_METADATA]) &&
+            is_array($state[self::KEY_IDENTITY_PROVIDER_METADATA])
+        ) {
+            return $state[self::KEY_IDENTITY_PROVIDER_METADATA];
+        } elseif (!empty($state[self::KEY_SOURCE]) && is_array($state[self::KEY_SOURCE])) {
+            return $state[self::KEY_SOURCE];
+        }
+
+        throw new UnexpectedValueException('State array does not contain IdP metadata.');
+    }
+
+    protected function resolveServiceProviderMetadata(array $state): array
+    {
+        if (
+            !empty($state[self::KEY_SERVICE_PROVIDER_METADATA]) &&
+            is_array($state[self::KEY_SERVICE_PROVIDER_METADATA])
+        ) {
+            return $state[self::KEY_SERVICE_PROVIDER_METADATA];
+        } elseif (!empty($state[self::KEY_DESTINATION]) && is_array($state[self::KEY_DESTINATION])) {
+            return $state[self::KEY_DESTINATION];
+        }
+
+        throw new UnexpectedValueException('State array does not contain SP metadata.');
+    }
+
+    protected function resolveIdentityProviderEntityId(): string
+    {
+        if (
+            !empty($this->identityProviderMetadata[Identity\Saml2::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->identityProviderMetadata[Identity\Saml2::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->identityProviderMetadata[Identity\Saml2::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('IdP metadata array does not contain entity ID.');
+    }
+
+    protected function resolveServiceProviderEntityId(): string
+    {
+        if (
+            !empty($this->serviceProviderMetadata[Service\Saml2::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->serviceProviderMetadata[Service\Saml2::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->serviceProviderMetadata[Service\Saml2::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('Service provider metadata array does not contain entity ID.');
+    }
+
+    public function getAuthenticationProtocol(): AuthenticationProtocolInterface
+    {
+        return new Protocol\Saml2();
+    }
+}
diff --git a/src/Entities/Authentication/Protocol/Bag.php b/src/Entities/Authentication/Protocol/Bag.php
new file mode 100644
index 0000000..af6b50b
--- /dev/null
+++ b/src/Entities/Authentication/Protocol/Bag.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication\Protocol;
+
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+
+class Bag
+{
+    /**
+     * @var array<int,AuthenticationProtocolInterface>
+     */
+    protected array $protocols = [];
+
+    public function __construct()
+    {
+        $saml2 = new Saml2();
+        $this->protocols[$saml2->getId()] = $saml2;
+        $oidc = new Oidc();
+        $this->protocols[$oidc->getId()] = $oidc;
+    }
+
+    public function getById(int $id): ?AuthenticationProtocolInterface
+    {
+        return $this->protocols[$id] ?? null;
+    }
+
+    public function getAll(): array
+    {
+        return $this->protocols;
+    }
+}
diff --git a/src/Entities/Authentication/Protocol/Oidc.php b/src/Entities/Authentication/Protocol/Oidc.php
new file mode 100644
index 0000000..40cc941
--- /dev/null
+++ b/src/Entities/Authentication/Protocol/Oidc.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication\Protocol;
+
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+
+class Oidc implements AuthenticationProtocolInterface
+{
+    public const DESIGNATION = 'OIDC';
+    public const ID = 2;
+
+    public function getDesignation(): string
+    {
+        return self::DESIGNATION;
+    }
+
+    public function getId(): int
+    {
+        return self::ID;
+    }
+}
diff --git a/src/Entities/Authentication/Protocol/Saml2.php b/src/Entities/Authentication/Protocol/Saml2.php
new file mode 100644
index 0000000..00ea90c
--- /dev/null
+++ b/src/Entities/Authentication/Protocol/Saml2.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication\Protocol;
+
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+
+class Saml2 implements AuthenticationProtocolInterface
+{
+    public const DESIGNATION = 'SAML2';
+    public const ID = 1;
+
+    public function getDesignation(): string
+    {
+        return self::DESIGNATION;
+    }
+
+    public function getId(): int
+    {
+        return self::ID;
+    }
+}
diff --git a/src/Entities/Bases/AbstractProvider.php b/src/Entities/Bases/AbstractProvider.php
index bad746a..f3833d5 100644
--- a/src/Entities/Bases/AbstractProvider.php
+++ b/src/Entities/Bases/AbstractProvider.php
@@ -4,14 +4,10 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Entities\Bases;
 
-use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface;
 
-abstract class AbstractProvider
+abstract class AbstractProvider implements ProviderInterface
 {
-    public const METADATA_KEY_NAME = 'name';
-    public const METADATA_KEY_ENTITY_ID = 'entityid';
-    public const METADATA_KEY_DESCRIPTION = 'description';
-
     protected array $metadata;
     protected string $entityId;
 
@@ -21,39 +17,6 @@ abstract class AbstractProvider
         $this->entityId = $this->resolveEntityId();
     }
 
-    public function getMetadata(): array
-    {
-        return $this->metadata;
-    }
-
-    public function getName(string $locale = 'en'): ?string
-    {
-        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale);
-    }
-
-    public function getEntityId(): string
-    {
-        return $this->entityId;
-    }
-
-    public function getDescription(string $locale = 'en'): ?string
-    {
-        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale);
-    }
-
-
-    protected function resolveEntityId(): string
-    {
-        if (
-            !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) &&
-            is_string($this->metadata[self::METADATA_KEY_ENTITY_ID])
-        ) {
-            return $this->metadata[self::METADATA_KEY_ENTITY_ID];
-        }
-
-        throw new UnexpectedValueException('Provider entity metadata does not contain entity ID.');
-    }
-
     protected function resolveOptionallyLocalizedString(string $key, string $locale = 'en'): ?string
     {
         if (!isset($this->metadata[$key])) {
@@ -75,4 +38,18 @@ abstract class AbstractProvider
 
         return null;
     }
+
+    public function getMetadata(): array
+    {
+        return $this->metadata;
+    }
+
+    public function getEntityId(): string
+    {
+        return $this->entityId;
+    }
+
+    abstract public function getName(string $locale = 'en'): ?string;
+    abstract public function getDescription(string $locale = 'en'): ?string;
+    abstract protected function resolveEntityId(): string;
 }
diff --git a/src/Entities/Authentication/State.php b/src/Entities/Bases/AbstractState.php
similarity index 59%
rename from src/Entities/Authentication/State.php
rename to src/Entities/Bases/AbstractState.php
index aa5378c..a2d5cd9 100644
--- a/src/Entities/Authentication/State.php
+++ b/src/Entities/Bases/AbstractState.php
@@ -2,25 +2,21 @@
 
 declare(strict_types=1);
 
-namespace SimpleSAML\Module\accounting\Entities\Authentication;
+namespace SimpleSAML\Module\accounting\Entities\Bases;
 
-use DateTimeImmutable;
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Entities\Interfaces\StateInterface;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
+use DateTimeImmutable;
 use Throwable;
 
-class State
+abstract class AbstractState implements StateInterface
 {
     public const KEY_ATTRIBUTES = 'Attributes';
-    public const KEY_AUTHENTICATION_INSTANT = 'AuthnInstant';
-    public const KEY_IDENTITY_PROVIDER_METADATA = 'IdPMetadata';
-    public const KEY_SOURCE = 'Source';
-    public const KEY_SERVICE_PROVIDER_METADATA = 'SPMetadata';
-    public const KEY_DESTINATION = 'Destination';
-
     public const KEY_ACCOUNTING = 'accounting';
     public const ACCOUNTING_KEY_CLIENT_IP_ADDRESS = 'client_ip_address';
+    public const KEY_AUTHENTICATION_INSTANT = 'AuthnInstant';
 
     protected string $identityProviderEntityId;
     protected string $serviceProviderEntityId;
@@ -49,29 +45,11 @@ class State
         $this->clientIpAddress = $this->resolveClientIpAddress($state);
     }
 
-    protected function resolveIdentityProviderEntityId(): string
-    {
-        if (
-            !empty($this->identityProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID]) &&
-            is_string($this->identityProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID])
-        ) {
-            return $this->identityProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID];
-        }
-
-        throw new UnexpectedValueException('IdP metadata array does not contain entity ID.');
-    }
-
-    protected function resolveServiceProviderEntityId(): string
-    {
-        if (
-            !empty($this->serviceProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID]) &&
-            is_string($this->serviceProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID])
-        ) {
-            return $this->serviceProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID];
-        }
-
-        throw new UnexpectedValueException('SP metadata array does not contain entity ID.');
-    }
+    abstract protected function resolveIdentityProviderMetadata(array $state): array;
+    abstract protected function resolveIdentityProviderEntityId(): string;
+    abstract protected function resolveServiceProviderMetadata(array $state): array;
+    abstract protected function resolveServiceProviderEntityId(): string;
+    abstract public function getAuthenticationProtocol(): AuthenticationProtocolInterface;
 
     protected function resolveAttributes(array $state): array
     {
@@ -82,33 +60,13 @@ class State
         return $state[self::KEY_ATTRIBUTES];
     }
 
-    public function getIdentityProviderEntityId(): string
-    {
-        return $this->identityProviderEntityId;
-    }
-
-    public function getServiceProviderEntityId(): string
-    {
-        return $this->serviceProviderEntityId;
-    }
-
-    public function getAttributes(): array
-    {
-        return $this->attributes;
-    }
-
-    public function getAttributeValue(string $attributeName): ?string
-    {
-        if (!empty($this->attributes[$attributeName]) && is_array($this->attributes[$attributeName])) {
-            return (string)reset($this->attributes[$attributeName]);
-        }
-
-        return null;
-    }
-
-    public function getCreatedAt(): DateTimeImmutable
+    protected function resolveClientIpAddress(array $state): ?string
     {
-        return $this->createdAt;
+        return $this->helpersManager->getNetwork()->resolveClientIpAddress(
+            isset($state[self::KEY_ACCOUNTING][self::ACCOUNTING_KEY_CLIENT_IP_ADDRESS]) ?
+                (string)$state[self::KEY_ACCOUNTING][self::ACCOUNTING_KEY_CLIENT_IP_ADDRESS]
+                : null
+        );
     }
 
     protected function resolveAuthenticationInstant(array $state): ?DateTimeImmutable
@@ -131,67 +89,59 @@ class State
         }
     }
 
-    public function getAuthenticationInstant(): ?DateTimeImmutable
+    public function getIdentityProviderEntityId(): string
     {
-        return $this->authenticationInstant;
+        return $this->identityProviderEntityId;
+    }
+
+    public function getServiceProviderEntityId(): string
+    {
+        return $this->serviceProviderEntityId;
+    }
+
+    public function getAttributes(): array
+    {
+        return $this->attributes;
     }
 
-    protected function resolveIdentityProviderMetadata(array $state): array
+    public function getFirstAttributeValue(string $attributeName): ?string
     {
-        if (
-            !empty($state[self::KEY_IDENTITY_PROVIDER_METADATA]) &&
-            is_array($state[self::KEY_IDENTITY_PROVIDER_METADATA])
-        ) {
-            return $state[self::KEY_IDENTITY_PROVIDER_METADATA];
-        } elseif (!empty($state[self::KEY_SOURCE]) && is_array($state[self::KEY_SOURCE])) {
-            return $state[self::KEY_SOURCE];
+        if (($value = $this->getAttributeValue($attributeName)) !== null) {
+            return (string)reset($value);
         }
 
-        throw new UnexpectedValueException('State array does not contain IdP metadata.');
+        return null;
     }
 
-    protected function resolveServiceProviderMetadata(array $state): array
+    public function getAttributeValue(string $attributeName): ?array
     {
-        if (
-            !empty($state[self::KEY_SERVICE_PROVIDER_METADATA]) &&
-            is_array($state[self::KEY_SERVICE_PROVIDER_METADATA])
-        ) {
-            return $state[self::KEY_SERVICE_PROVIDER_METADATA];
-        } elseif (!empty($state[self::KEY_DESTINATION]) && is_array($state[self::KEY_DESTINATION])) {
-            return $state[self::KEY_DESTINATION];
+        if (!empty($this->attributes[$attributeName]) && is_array($this->attributes[$attributeName])) {
+            return $this->attributes[$attributeName];
         }
 
-        throw new UnexpectedValueException('State array does not contain SP metadata.');
+        return null;
+    }
+
+    public function getCreatedAt(): DateTimeImmutable
+    {
+        return $this->createdAt;
+    }
+
+    public function getAuthenticationInstant(): ?DateTimeImmutable
+    {
+        return $this->authenticationInstant;
     }
 
-    /**
-     * @return array
-     */
     public function getIdentityProviderMetadata(): array
     {
         return $this->identityProviderMetadata;
     }
 
-    /**
-     * @return array
-     */
     public function getServiceProviderMetadata(): array
     {
         return $this->serviceProviderMetadata;
     }
 
-    protected function resolveClientIpAddress(array $state): ?string
-    {
-        return $this->helpersManager->getNetworkHelper()->resolveClientIpAddress(
-            isset($state[self::KEY_ACCOUNTING][self::ACCOUNTING_KEY_CLIENT_IP_ADDRESS]) ?
-                (string)$state[self::KEY_ACCOUNTING][self::ACCOUNTING_KEY_CLIENT_IP_ADDRESS]
-                : null
-        );
-    }
-
-    /**
-     * @return string|null
-     */
     public function getClientIpAddress(): ?string
     {
         return $this->clientIpAddress;
diff --git a/src/Entities/ConnectedServiceProvider.php b/src/Entities/ConnectedServiceProvider.php
index 7c4b7e7..b1ded7a 100644
--- a/src/Entities/ConnectedServiceProvider.php
+++ b/src/Entities/ConnectedServiceProvider.php
@@ -5,27 +5,28 @@ declare(strict_types=1);
 namespace SimpleSAML\Module\accounting\Entities;
 
 use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
 
 /**
  * Represents a Service Provider to which a user has authenticated at least once.
  */
 class ConnectedServiceProvider
 {
-    protected ServiceProvider $serviceProvider;
+    protected ServiceProviderInterface $serviceProvider;
     protected int $numberOfAuthentications;
     protected DateTimeImmutable $lastAuthenticationAt;
     protected DateTimeImmutable $firstAuthenticationAt;
     protected User $user;
 
     /**
-     * @param ServiceProvider $serviceProvider
+     * @param ServiceProviderInterface $serviceProvider
      * @param int $numberOfAuthentications
      * @param DateTimeImmutable $lastAuthenticationAt
      * @param DateTimeImmutable $firstAuthenticationAt
      * @param User $user
      */
     public function __construct(
-        ServiceProvider $serviceProvider,
+        ServiceProviderInterface $serviceProvider,
         int $numberOfAuthentications,
         DateTimeImmutable $lastAuthenticationAt,
         DateTimeImmutable $firstAuthenticationAt,
@@ -39,9 +40,9 @@ class ConnectedServiceProvider
     }
 
     /**
-     * @return ServiceProvider
+     * @return ServiceProviderInterface
      */
-    public function getServiceProvider(): ServiceProvider
+    public function getServiceProvider(): ServiceProviderInterface
     {
         return $this->serviceProvider;
     }
diff --git a/src/Entities/IdentityProvider.php b/src/Entities/IdentityProvider.php
deleted file mode 100644
index 3207e91..0000000
--- a/src/Entities/IdentityProvider.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Module\accounting\Entities;
-
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
-
-class IdentityProvider extends AbstractProvider
-{
-}
diff --git a/src/Entities/Interfaces/AuthenticationProtocolInterface.php b/src/Entities/Interfaces/AuthenticationProtocolInterface.php
new file mode 100644
index 0000000..18375c1
--- /dev/null
+++ b/src/Entities/Interfaces/AuthenticationProtocolInterface.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Interfaces;
+
+interface AuthenticationProtocolInterface
+{
+    public function getDesignation(): string;
+    public function getId(): int;
+}
diff --git a/src/Entities/Interfaces/IdentityProviderInterface.php b/src/Entities/Interfaces/IdentityProviderInterface.php
new file mode 100644
index 0000000..d36412d
--- /dev/null
+++ b/src/Entities/Interfaces/IdentityProviderInterface.php
@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Interfaces;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+interface IdentityProviderInterface extends ProviderInterface
+{
+}
diff --git a/src/Entities/Interfaces/ProviderInterface.php b/src/Entities/Interfaces/ProviderInterface.php
new file mode 100644
index 0000000..30971b6
--- /dev/null
+++ b/src/Entities/Interfaces/ProviderInterface.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Interfaces;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+interface ProviderInterface
+{
+    public function getMetadata(): array;
+    public function getName(string $locale = 'en'): ?string;
+    public function getEntityId(): string;
+    public function getDescription(string $locale = 'en'): ?string;
+}
diff --git a/src/Entities/Interfaces/ServiceProviderInterface.php b/src/Entities/Interfaces/ServiceProviderInterface.php
new file mode 100644
index 0000000..bde2d19
--- /dev/null
+++ b/src/Entities/Interfaces/ServiceProviderInterface.php
@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Interfaces;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+interface ServiceProviderInterface extends ProviderInterface
+{
+}
diff --git a/src/Entities/Interfaces/StateInterface.php b/src/Entities/Interfaces/StateInterface.php
new file mode 100644
index 0000000..bed1e19
--- /dev/null
+++ b/src/Entities/Interfaces/StateInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Interfaces;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+interface StateInterface
+{
+    public function getIdentityProviderEntityId(): string;
+    public function getServiceProviderEntityId(): string;
+    public function getAttributes(): array;
+    public function getFirstAttributeValue(string $attributeName): ?string;
+    public function getCreatedAt(): DateTimeImmutable;
+    public function getAuthenticationInstant(): ?DateTimeImmutable;
+    public function getIdentityProviderMetadata(): array;
+    public function getServiceProviderMetadata(): array;
+    public function getClientIpAddress(): ?string;
+    public function getAuthenticationProtocol(): AuthenticationProtocolInterface;
+}
diff --git a/src/Entities/Providers/Identity/Oidc.php b/src/Entities/Providers/Identity/Oidc.php
new file mode 100644
index 0000000..660a850
--- /dev/null
+++ b/src/Entities/Providers/Identity/Oidc.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Providers\Identity;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+class Oidc extends AbstractProvider implements IdentityProviderInterface
+{
+    public const METADATA_KEY_ENTITY_ID = 'issuer';
+
+    public function getName(string $locale = 'en'): ?string
+    {
+        return null;
+    }
+
+    public function getDescription(string $locale = 'en'): ?string
+    {
+        return null;
+    }
+
+    /**
+     * @throws MetadataException
+     */
+    protected function resolveEntityId(): string
+    {
+        if (
+            !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->metadata[self::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->metadata[self::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new MetadataException('OpenID Provider metadata does not contain entity ID.');
+    }
+}
diff --git a/src/Entities/Providers/Identity/Saml2.php b/src/Entities/Providers/Identity/Saml2.php
new file mode 100644
index 0000000..06bd939
--- /dev/null
+++ b/src/Entities/Providers/Identity/Saml2.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Providers\Identity;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+class Saml2 extends AbstractProvider implements IdentityProviderInterface
+{
+    public const METADATA_KEY_NAME = 'name';
+    public const METADATA_KEY_ENTITY_ID = 'entityid';
+    public const METADATA_KEY_DESCRIPTION = 'description';
+
+    public function getName(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale);
+    }
+
+    public function getDescription(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale);
+    }
+
+    /**
+     * @throws MetadataException
+     */
+    protected function resolveEntityId(): string
+    {
+        if (
+            !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->metadata[self::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->metadata[self::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new MetadataException('Identity provider metadata does not contain entity ID.');
+    }
+}
diff --git a/src/Entities/Providers/Service/Oidc.php b/src/Entities/Providers/Service/Oidc.php
new file mode 100644
index 0000000..37e187b
--- /dev/null
+++ b/src/Entities/Providers/Service/Oidc.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Providers\Service;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+class Oidc extends AbstractProvider implements ServiceProviderInterface
+{
+    public const METADATA_KEY_ENTITY_ID = 'id';
+    public const METADATA_KEY_NAME = 'name';
+    public const METADATA_KEY_DESCRIPTION = 'description';
+
+    public function getName(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale);
+    }
+
+    public function getDescription(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale);
+    }
+
+    /**
+     * @throws MetadataException
+     */
+    protected function resolveEntityId(): string
+    {
+        if (
+            !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->metadata[self::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->metadata[self::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new MetadataException('Relying Provider metadata does not contain entity ID.');
+    }
+}
diff --git a/src/Entities/Providers/Service/Saml2.php b/src/Entities/Providers/Service/Saml2.php
new file mode 100644
index 0000000..d88bfae
--- /dev/null
+++ b/src/Entities/Providers/Service/Saml2.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Providers\Service;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+class Saml2 extends AbstractProvider implements ServiceProviderInterface
+{
+    public const METADATA_KEY_ENTITY_ID = 'entityid';
+    public const METADATA_KEY_NAME = 'name';
+    public const METADATA_KEY_DESCRIPTION = 'description';
+
+    public function getName(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale);
+    }
+
+    public function getDescription(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale);
+    }
+
+    /**
+     * @throws MetadataException
+     */
+    protected function resolveEntityId(): string
+    {
+        if (
+            !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->metadata[self::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->metadata[self::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new MetadataException('Service provider metadata does not contain entity ID.');
+    }
+}
diff --git a/src/Entities/ServiceProvider.php b/src/Entities/ServiceProvider.php
deleted file mode 100644
index c5696c8..0000000
--- a/src/Entities/ServiceProvider.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Module\accounting\Entities;
-
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
-
-class ServiceProvider extends AbstractProvider
-{
-}
diff --git a/src/Exceptions/MetadataException.php b/src/Exceptions/MetadataException.php
new file mode 100644
index 0000000..80050db
--- /dev/null
+++ b/src/Exceptions/MetadataException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+use Exception;
+
+class MetadataException extends Exception
+{
+}
diff --git a/src/Exceptions/StateException.php b/src/Exceptions/StateException.php
new file mode 100644
index 0000000..640a813
--- /dev/null
+++ b/src/Exceptions/StateException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+use Exception;
+
+class StateException extends Exception
+{
+}
diff --git a/src/Helpers/ArrayHelper.php b/src/Helpers/Arr.php
similarity index 95%
rename from src/Helpers/ArrayHelper.php
rename to src/Helpers/Arr.php
index 7aec51f..be464ee 100644
--- a/src/Helpers/ArrayHelper.php
+++ b/src/Helpers/Arr.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Helpers;
 
-class ArrayHelper
+class Arr
 {
     public function recursivelySortByKey(array &$array): void
     {
diff --git a/src/Helpers/AttributesHelper.php b/src/Helpers/Attributes.php
similarity index 88%
rename from src/Helpers/AttributesHelper.php
rename to src/Helpers/Attributes.php
index 8fc6806..1bd940f 100644
--- a/src/Helpers/AttributesHelper.php
+++ b/src/Helpers/Attributes.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Helpers;
 
-class AttributesHelper
+class Attributes
 {
     /**
      * Map files which translate attribute names to (more) user-friendly format.
@@ -12,7 +12,7 @@ class AttributesHelper
     public const MAP_FILES_TO_NAME = ['facebook2name.php', 'linkedin2name.php', 'oid2name.php', 'openid2name.php',
         'removeurnprefix.php', 'twitter2name.php', 'urn2name.php', 'windowslive2name.php'];
 
-    public static function getMergedAttributeMapForFiles(string $sspBaseDirectory, array $mapFiles): array
+    public function getMergedAttributeMapForFiles(string $sspBaseDirectory, array $mapFiles): array
     {
         // This is the variable name used in map files. It is set to empty array by default, but later populated
         // by each include of the map file.
diff --git a/src/Helpers/AuthenticationEventStateResolver.php b/src/Helpers/AuthenticationEventStateResolver.php
new file mode 100644
index 0000000..27fe669
--- /dev/null
+++ b/src/Helpers/AuthenticationEventStateResolver.php
@@ -0,0 +1,53 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Oidc;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractState;
+use SimpleSAML\Module\accounting\Entities\Interfaces\StateInterface;
+use SimpleSAML\Module\accounting\Exceptions\StateException;
+
+use function array_key_exists;
+
+class AuthenticationEventStateResolver
+{
+    /**
+     * @throws StateException
+     */
+    public function fromStateArray(array $state): StateInterface
+    {
+        if (
+            ! array_key_exists(AbstractState::KEY_ATTRIBUTES, $state) ||
+            ! is_array($state[AbstractState::KEY_ATTRIBUTES])
+        ) {
+            throw new StateException('State array does not contain user attributes.');
+        }
+
+        if (
+            array_key_exists(Saml2::KEY_IDENTITY_PROVIDER_METADATA, $state) &&
+            is_array($state[Saml2::KEY_IDENTITY_PROVIDER_METADATA]) &&
+            array_key_exists(Saml2::KEY_SERVICE_PROVIDER_METADATA, $state) &&
+            is_array($state[Saml2::KEY_SERVICE_PROVIDER_METADATA])
+        ) {
+            // Authentication was done using SAML2 protocol...
+            return new Saml2($state);
+        }
+
+        $oidcRelatedState = (array)($state[Oidc::KEY_OIDC] ?? []);
+
+        if (
+            array_key_exists(Oidc::KEY_OPEN_ID_PROVIDER_METADATA, $oidcRelatedState) &&
+            is_array($oidcRelatedState[Oidc::KEY_OPEN_ID_PROVIDER_METADATA]) &&
+            array_key_exists(Oidc::KEY_RELYING_PARTY_METADATA, $oidcRelatedState) &&
+            is_array($oidcRelatedState[Oidc::KEY_RELYING_PARTY_METADATA])
+        ) {
+            // Authentication was done using OIDC protocol...
+            return new Oidc($state);
+        }
+
+        throw new StateException('Can not resolve state instance for particular authentication protocol.');
+    }
+}
diff --git a/src/Helpers/DateTimeHelper.php b/src/Helpers/DateTime.php
similarity index 96%
rename from src/Helpers/DateTimeHelper.php
rename to src/Helpers/DateTime.php
index 1e13c71..1e32817 100644
--- a/src/Helpers/DateTimeHelper.php
+++ b/src/Helpers/DateTime.php
@@ -7,7 +7,7 @@ namespace SimpleSAML\Module\accounting\Helpers;
 use DateInterval;
 use DateTimeImmutable;
 
-class DateTimeHelper
+class DateTime
 {
     /**
      * Convert date interval to seconds, interval being minimum 1 second.
diff --git a/src/Helpers/EnvironmentHelper.php b/src/Helpers/Environment.php
similarity index 88%
rename from src/Helpers/EnvironmentHelper.php
rename to src/Helpers/Environment.php
index 1e3f27d..19c4f81 100644
--- a/src/Helpers/EnvironmentHelper.php
+++ b/src/Helpers/Environment.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Helpers;
 
-class EnvironmentHelper
+class Environment
 {
     public function isCli(): bool
     {
diff --git a/src/Helpers/FilesystemHelper.php b/src/Helpers/Filesystem.php
similarity index 95%
rename from src/Helpers/FilesystemHelper.php
rename to src/Helpers/Filesystem.php
index 1ee6922..afd9d67 100644
--- a/src/Helpers/FilesystemHelper.php
+++ b/src/Helpers/Filesystem.php
@@ -6,7 +6,7 @@ namespace SimpleSAML\Module\accounting\Helpers;
 
 use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
 
-class FilesystemHelper
+class Filesystem
 {
     public function getRealPath(string $path): string
     {
diff --git a/src/Helpers/HashHelper.php b/src/Helpers/Hash.php
similarity index 78%
rename from src/Helpers/HashHelper.php
rename to src/Helpers/Hash.php
index ea38562..db09f4b 100644
--- a/src/Helpers/HashHelper.php
+++ b/src/Helpers/Hash.php
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Helpers;
 
-class HashHelper
+class Hash
 {
-    protected ArrayHelper $arrayHelper;
+    protected Arr $arrayHelper;
 
-    public function __construct(ArrayHelper $arrayHelper)
+    public function __construct(Arr $arrayHelper)
     {
         $this->arrayHelper = $arrayHelper;
     }
diff --git a/src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php b/src/Helpers/InstanceBuilderUsingModuleConfiguration.php
similarity index 94%
rename from src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php
rename to src/Helpers/InstanceBuilderUsingModuleConfiguration.php
index 0d8b2bb..7b10877 100644
--- a/src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php
+++ b/src/Helpers/InstanceBuilderUsingModuleConfiguration.php
@@ -14,8 +14,10 @@ use Throwable;
 
 use function sprintf;
 
-class InstanceBuilderUsingModuleConfigurationHelper
+class InstanceBuilderUsingModuleConfiguration
 {
+    public const BUILD_METHOD = 'build';
+
     /**
      * @param class-string $class
      * @param ModuleConfiguration $moduleConfiguration
@@ -30,7 +32,7 @@ class InstanceBuilderUsingModuleConfigurationHelper
         ModuleConfiguration $moduleConfiguration,
         LoggerInterface $logger,
         array $additionalArguments = [],
-        string $method = BuildableUsingModuleConfigurationInterface::BUILD_METHOD
+        string $method = self::BUILD_METHOD
     ): BuildableUsingModuleConfigurationInterface {
         try {
             $this->validateClass($class);
diff --git a/src/Helpers/ModuleRoutesHelper.php b/src/Helpers/ModuleRoutes.php
similarity index 78%
rename from src/Helpers/ModuleRoutesHelper.php
rename to src/Helpers/ModuleRoutes.php
index e23ee2f..f03617f 100644
--- a/src/Helpers/ModuleRoutesHelper.php
+++ b/src/Helpers/ModuleRoutes.php
@@ -9,7 +9,7 @@ use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Utils\HTTP;
 
-class ModuleRoutesHelper
+class ModuleRoutes
 {
     public const PATH_ADMIN_CONFIGURATION_STATUS = 'admin/configuration/status';
 
@@ -26,9 +26,12 @@ class ModuleRoutesHelper
     {
         try {
             $url = $this->sspHttpUtils->getBaseURL() . 'module.php/' . ModuleConfiguration::MODULE_NAME . '/' . $path;
+            // @codeCoverageIgnoreStart
+            // SSP dumps some exception context data when simulating exception, so will ignore coverage for this...
         } catch (CriticalConfigurationError $exception) {
             $message = \sprintf('Could not load SimpleSAMLphp base URL. Error was: %s', $exception->getMessage());
-            throw new InvalidConfigurationException($message, (int)$exception->getCode(), $exception);
+            throw new InvalidConfigurationException($message, $exception->getCode(), $exception);
+            // @codeCoverageIgnoreEnd
         }
 
         if (!empty($parameters)) {
diff --git a/src/Helpers/NetworkHelper.php b/src/Helpers/Network.php
similarity index 97%
rename from src/Helpers/NetworkHelper.php
rename to src/Helpers/Network.php
index 8fa60ff..b9e5cbb 100644
--- a/src/Helpers/NetworkHelper.php
+++ b/src/Helpers/Network.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Helpers;
 
-class NetworkHelper
+class Network
 {
     public function resolveClientIpAddress(string $clientIpAddress = null): ?string
     {
diff --git a/src/Helpers/ProviderResolver.php b/src/Helpers/ProviderResolver.php
new file mode 100644
index 0000000..9933926
--- /dev/null
+++ b/src/Helpers/ProviderResolver.php
@@ -0,0 +1,54 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+use SimpleSAML\Module\accounting\Entities\Providers\Service;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity;
+
+class ProviderResolver
+{
+    /**
+     * @throws MetadataException
+     */
+    public function forIdentityFromMetadataArray(array $metadata): IdentityProviderInterface
+    {
+        try {
+            return new Identity\Saml2($metadata);
+        } catch (\Throwable $throwable) {
+            // This is not SAML2...
+        }
+
+        try {
+            return new Identity\Oidc($metadata);
+        } catch (\Throwable $throwable) {
+            // This is not OIDC...
+        }
+
+        throw new MetadataException('Can not resolve identity provider form provided metadata array.');
+    }
+
+    /**
+     * @throws MetadataException
+     */
+    public function forServiceFromMetadataArray(array $metadata): ServiceProviderInterface
+    {
+        try {
+            return new Service\Saml2($metadata);
+        } catch (\Throwable $throwable) {
+            // This is not SAML2...
+        }
+
+        try {
+            return new Service\Oidc($metadata);
+        } catch (\Throwable $throwable) {
+            // This is not OIDC...
+        }
+
+        throw new MetadataException('Can not resolve service provider form provided metadata array.');
+    }
+}
diff --git a/src/Helpers/RandomHelper.php b/src/Helpers/Random.php
similarity index 95%
rename from src/Helpers/RandomHelper.php
rename to src/Helpers/Random.php
index 0d773cf..e56fde7 100644
--- a/src/Helpers/RandomHelper.php
+++ b/src/Helpers/Random.php
@@ -6,7 +6,7 @@ namespace SimpleSAML\Module\accounting\Helpers;
 
 use Throwable;
 
-class RandomHelper
+class Random
 {
     public function getRandomInt(int $minimum = PHP_INT_MIN, int $maximum = PHP_INT_MAX): int
     {
diff --git a/src/Http/Controllers/Admin/Configuration.php b/src/Http/Controllers/Admin/Configuration.php
index fa2adaa..3ce9922 100644
--- a/src/Http/Controllers/Admin/Configuration.php
+++ b/src/Http/Controllers/Admin/Configuration.php
@@ -7,7 +7,7 @@ namespace SimpleSAML\Module\accounting\Http\Controllers\Admin;
 use Exception;
 use Psr\Log\LoggerInterface;
 use SimpleSAML\Configuration as SspConfiguration;
-use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
 use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
@@ -18,6 +18,9 @@ use SimpleSAML\XHTML\Template;
 use Symfony\Component\HttpFoundation\Request;
 use Throwable;
 
+/**
+ * @psalm-suppress UnusedClass Used as route controller.
+ */
 class Configuration
 {
     protected SspConfiguration $sspConfiguration;
@@ -116,8 +119,8 @@ class Configuration
             'defaultDataTrackerAndProvider' => $defaultDataTrackerAndProvider,
             'additionalTrackers' => $additionalTrackers,
             'setupNeeded' => $setupNeeded,
-            'profilePageUri' => $this->helpersManager->getModuleRoutesHelper()
-                ->getUrl(ModuleRoutesHelper::PATH_USER_PERSONAL_DATA),
+            'profilePageUri' => $this->helpersManager->getModuleRoutes()
+                ->getUrl(ModuleRoutes::PATH_USER_PERSONAL_DATA),
         ];
 
         $template = new Template($this->sspConfiguration, 'accounting:admin/configuration/status.twig');
diff --git a/src/Http/Controllers/User/Profile.php b/src/Http/Controllers/User/Profile.php
index 34b3212..5ef9218 100644
--- a/src/Http/Controllers/User/Profile.php
+++ b/src/Http/Controllers/User/Profile.php
@@ -12,7 +12,7 @@ use SimpleSAML\Error\CriticalConfigurationError;
 use SimpleSAML\HTTP\RunnableResponse;
 use SimpleSAML\Module\accounting\Exceptions\Exception;
 use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
-use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
+use SimpleSAML\Module\accounting\Helpers\Attributes;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Module\accounting\ModuleConfiguration\ConnectionType;
 use SimpleSAML\Module\accounting\Providers\Builders\AuthenticationDataProviderBuilder;
@@ -23,6 +23,9 @@ use SimpleSAML\XHTML\Template;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 
+/**
+ * @psalm-suppress UnusedClass Used as route controller.
+ */
 class Profile
 {
     protected ModuleConfiguration $moduleConfiguration;
@@ -72,7 +75,7 @@ class Profile
     /**
      * @throws ConfigurationError
      */
-    public function personalData(Request $request): Response
+    public function personalData(): Response
     {
         $normalizedAttributes = [];
 
@@ -100,7 +103,7 @@ class Profile
      * @throws Exception
      * @throws ConfigurationError
      */
-    public function connectedOrganizations(Request $request): Template
+    public function connectedOrganizations(): Template
     {
         $userIdentifier = $this->resolveUserIdentifier();
 
@@ -176,7 +179,7 @@ class Profile
             return $this->sspConfiguration->getBasePath() . 'logout.php';
         } catch (CriticalConfigurationError $exception) {
             $message = \sprintf('Could not resolve SimpleSAMLphp base path. Error was: %s', $exception->getMessage());
-            throw new InvalidConfigurationException($message, (int)$exception->getCode(), $exception);
+            throw new InvalidConfigurationException($message, $exception->getCode(), $exception);
         }
     }
 
@@ -185,9 +188,9 @@ class Profile
      */
     protected function prepareToNameAttributeMap(): array
     {
-        return $this->helpersManager->getAttributesHelper()->getMergedAttributeMapForFiles(
+        return $this->helpersManager->getAttributes()->getMergedAttributeMapForFiles(
             $this->sspConfiguration->getBaseDir(),
-            AttributesHelper::MAP_FILES_TO_NAME
+            Attributes::MAP_FILES_TO_NAME
         );
     }
 
diff --git a/src/Interfaces/BuildableUsingModuleConfigurationInterface.php b/src/Interfaces/BuildableUsingModuleConfigurationInterface.php
index 4b56a46..9619dbe 100644
--- a/src/Interfaces/BuildableUsingModuleConfigurationInterface.php
+++ b/src/Interfaces/BuildableUsingModuleConfigurationInterface.php
@@ -9,7 +9,5 @@ use SimpleSAML\Module\accounting\ModuleConfiguration;
 
 interface BuildableUsingModuleConfigurationInterface
 {
-    public const BUILD_METHOD = 'build';
-
     public static function build(ModuleConfiguration $moduleConfiguration, LoggerInterface $logger): self;
 }
diff --git a/src/ModuleConfiguration.php b/src/ModuleConfiguration.php
index 21e5d69..e4e9e13 100644
--- a/src/ModuleConfiguration.php
+++ b/src/ModuleConfiguration.php
@@ -230,14 +230,6 @@ class ModuleConfiguration
         return $connectionKey;
     }
 
-    /**
-     * @throws InvalidConfigurationException
-     */
-    public function getClassConnectionParameters(string $class, string $connectionType = ConnectionType::MASTER): array
-    {
-        return $this->getConnectionParameters($this->getClassConnectionKey($class, $connectionType));
-    }
-
     /**
      * @throws InvalidConfigurationException
      */
diff --git a/src/Providers/Builders/AuthenticationDataProviderBuilder.php b/src/Providers/Builders/AuthenticationDataProviderBuilder.php
index db0349e..1bc13f3 100644
--- a/src/Providers/Builders/AuthenticationDataProviderBuilder.php
+++ b/src/Providers/Builders/AuthenticationDataProviderBuilder.php
@@ -48,7 +48,7 @@ class AuthenticationDataProviderBuilder
 
             // Build...
             /** @var AuthenticationDataProviderInterface $store */
-            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()->build(
+            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfiguration()->build(
                 $class,
                 $this->moduleConfiguration,
                 $this->logger,
diff --git a/src/Services/HelpersManager.php b/src/Services/HelpersManager.php
index e66518f..e61c64d 100644
--- a/src/Services/HelpersManager.php
+++ b/src/Services/HelpersManager.php
@@ -4,77 +4,92 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Services;
 
-use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
-use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
-use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
-use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
-use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
-use SimpleSAML\Module\accounting\Helpers\HashHelper;
-use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
-use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
-use SimpleSAML\Module\accounting\Helpers\RandomHelper;
-use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\Helpers\Arr;
+use SimpleSAML\Module\accounting\Helpers\Attributes;
+use SimpleSAML\Module\accounting\Helpers\AuthenticationEventStateResolver;
+use SimpleSAML\Module\accounting\Helpers\DateTime;
+use SimpleSAML\Module\accounting\Helpers\Environment;
+use SimpleSAML\Module\accounting\Helpers\Filesystem;
+use SimpleSAML\Module\accounting\Helpers\Hash;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration;
+use SimpleSAML\Module\accounting\Helpers\Network;
+use SimpleSAML\Module\accounting\Helpers\ProviderResolver;
+use SimpleSAML\Module\accounting\Helpers\Random;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
 
 class HelpersManager
 {
-    protected static ?DateTimeHelper $dateTimeHelper;
-    protected static ?EnvironmentHelper $environmentHelper;
-    protected static ?RandomHelper $randomHelper;
-    protected static ?ModuleRoutesHelper $routesHelper;
-    protected static ?ArrayHelper $arrayHelper;
-    protected static ?HashHelper $hashHelper;
-    protected static ?AttributesHelper $attributesHelper;
-    protected static ?FilesystemHelper $filesystemHelper;
-    protected static ?InstanceBuilderUsingModuleConfigurationHelper $instanceBuilderHelper;
-    protected static ?NetworkHelper $networkHelper;
-
-    public function getDateTimeHelper(): DateTimeHelper
+    protected static ?DateTime $dateTime;
+    protected static ?Environment $environment;
+    protected static ?Random $random;
+    protected static ?ModuleRoutes $routes;
+    protected static ?Arr $arr;
+    protected static ?Hash $hash;
+    protected static ?Attributes $attributes;
+    protected static ?Filesystem $filesystem;
+    protected static ?InstanceBuilderUsingModuleConfiguration $instanceBuilder;
+    protected static ?Network $network;
+    protected static ?AuthenticationEventStateResolver $authenticationEventStateResolver;
+    protected static ?ProviderResolver $providerResolver;
+
+
+    public function getDateTime(): DateTime
+    {
+        return self::$dateTime ??= new DateTime();
+    }
+
+    public function getEnvironment(): Environment
+    {
+        return self::$environment ??= new Environment();
+    }
+
+    public function getRandom(): Random
     {
-        return self::$dateTimeHelper ??= new DateTimeHelper();
+        return self::$random ??= new Random();
     }
 
-    public function getEnvironmentHelper(): EnvironmentHelper
+    public function getModuleRoutes(): ModuleRoutes
     {
-        return self::$environmentHelper ??= new EnvironmentHelper();
+        return self::$routes ??= new ModuleRoutes();
     }
 
-    public function getRandomHelper(): RandomHelper
+    public function getArr(): Arr
     {
-        return self::$randomHelper ??= new RandomHelper();
+        return self::$arr ??= new Arr();
     }
 
-    public function getModuleRoutesHelper(): ModuleRoutesHelper
+    public function getHash(): Hash
     {
-        return self::$routesHelper ??= new ModuleRoutesHelper();
+        return self::$hash ??= new Hash($this->getArr());
     }
 
-    public function getArrayHelper(): ArrayHelper
+    public function getAttributes(): Attributes
     {
-        return self::$arrayHelper ??= new ArrayHelper();
+        return self::$attributes ??= new Attributes();
     }
 
-    public function getHashHelper(): HashHelper
+    public function getFilesystem(): Filesystem
     {
-        return self::$hashHelper ??= new HashHelper($this->getArrayHelper());
+        return self::$filesystem ??= new Filesystem();
     }
 
-    public function getAttributesHelper(): AttributesHelper
+    public function getInstanceBuilderUsingModuleConfiguration(): InstanceBuilderUsingModuleConfiguration
     {
-        return self::$attributesHelper ??= new AttributesHelper();
+        return self::$instanceBuilder ??= new InstanceBuilderUsingModuleConfiguration();
     }
 
-    public function getFilesystemHelper(): FilesystemHelper
+    public function getNetwork(): Network
     {
-        return self::$filesystemHelper ??= new FilesystemHelper();
+        return self::$network ??= new Network();
     }
 
-    public function getInstanceBuilderUsingModuleConfigurationHelper(): InstanceBuilderUsingModuleConfigurationHelper
+    public function getAuthenticationEventStateResolver(): AuthenticationEventStateResolver
     {
-        return self::$instanceBuilderHelper ??= new InstanceBuilderUsingModuleConfigurationHelper();
+        return self::$authenticationEventStateResolver ??= new AuthenticationEventStateResolver();
     }
 
-    public function getNetworkHelper(): NetworkHelper
+    public function getProviderResolver(): ProviderResolver
     {
-        return self::$networkHelper ??= new NetworkHelper();
+        return self::$providerResolver ??= new ProviderResolver();
     }
 }
diff --git a/src/Services/JobRunner.php b/src/Services/JobRunner.php
index 6b07f2b..0e9fc05 100644
--- a/src/Services/JobRunner.php
+++ b/src/Services/JobRunner.php
@@ -79,7 +79,7 @@ class JobRunner
 
         $this->cache = $cache ?? $this->resolveCache();
 
-        $this->jobRunnerId = $this->helpersManager->getRandomHelper()->getRandomInt();
+        $this->jobRunnerId = $this->helpersManager->getRandom()->getRandomInt();
 
         $this->state = $state ?? new State($this->jobRunnerId);
 
@@ -291,6 +291,7 @@ class JobRunner
 
     /**
      * @throws Exception
+     * @psalm-suppress PossiblyUnusedMethod
      */
     protected function validateSelfState(): void
     {
@@ -509,7 +510,7 @@ class JobRunner
 
     protected function isCli(): bool
     {
-        return $this->helpersManager->getEnvironmentHelper()->isCli();
+        return $this->helpersManager->getEnvironment()->isCli();
     }
 
     /**
@@ -575,7 +576,7 @@ class JobRunner
 
         // Use the shorter interval from the two...
         $maximumExecutionTimeSeconds = $this->helpersManager
-            ->getDateTimeHelper()
+            ->getDateTime()
             ->convertDateIntervalToSeconds($maximumExecutionTime);
 
         if ($iniMaximumExecutionTimeSeconds < $maximumExecutionTimeSeconds) {
@@ -586,6 +587,9 @@ class JobRunner
         return $maximumExecutionTime;
     }
 
+    /**
+     * @psalm-suppress PossiblyUnusedMethod
+     */
     protected function isMaximumExecutionTimeReached(): bool
     {
         if ($this->maximumExecutionTime === null) {
diff --git a/src/Services/JobRunner/RateLimiter.php b/src/Services/JobRunner/RateLimiter.php
index c4c4257..6f7bf07 100644
--- a/src/Services/JobRunner/RateLimiter.php
+++ b/src/Services/JobRunner/RateLimiter.php
@@ -25,10 +25,10 @@ class RateLimiter
     ) {
         $this->helpersManager = $helpersManager ?? new HelpersManager();
 
-        $this->maxPauseInSeconds = $this->helpersManager->getDateTimeHelper()->convertDateIntervalToSeconds(
+        $this->maxPauseInSeconds = $this->helpersManager->getDateTime()->convertDateIntervalToSeconds(
             $maxPauseInterval ?? new DateInterval(self::DEFAULT_MAX_PAUSE_DURATION)
         );
-        $this->maxBackoffPauseInSeconds = $this->helpersManager->getDateTimeHelper()->convertDateIntervalToSeconds(
+        $this->maxBackoffPauseInSeconds = $this->helpersManager->getDateTime()->convertDateIntervalToSeconds(
             $maxBackoffInterval ?? new DateInterval(self::DEFAULT_MAX_BACKOFF_PAUSE_DURATION)
         );
     }
diff --git a/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php b/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php
index 28150f4..c832bd8 100644
--- a/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php
+++ b/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php
@@ -11,6 +11,9 @@ use Doctrine\DBAL\Types\Types;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
 use Throwable;
 
+/**
+ * @psalm-api
+ */
 abstract class AbstractRawEntity
 {
     protected array $rawRow;
diff --git a/src/Stores/Builders/Bases/AbstractStoreBuilder.php b/src/Stores/Builders/Bases/AbstractStoreBuilder.php
index 5cce33d..45c9321 100644
--- a/src/Stores/Builders/Bases/AbstractStoreBuilder.php
+++ b/src/Stores/Builders/Bases/AbstractStoreBuilder.php
@@ -49,7 +49,7 @@ abstract class AbstractStoreBuilder
 
             // Build store...
             /** @var StoreInterface $store */
-            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()->build(
+            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfiguration()->build(
                 $class,
                 $this->moduleConfiguration,
                 $this->logger,
diff --git a/src/Stores/Connections/Bases/AbstractMigrator.php b/src/Stores/Connections/Bases/AbstractMigrator.php
index caa8166..ae7e0fe 100644
--- a/src/Stores/Connections/Bases/AbstractMigrator.php
+++ b/src/Stores/Connections/Bases/AbstractMigrator.php
@@ -28,7 +28,7 @@ abstract class AbstractMigrator
      */
     public function gatherMigrationClassesFromDirectory(string $directory, string $namespace): array
     {
-        $directory = $this->helpersManager->getFilesystemHelper()->getRealPath($directory);
+        $directory = $this->helpersManager->getFilesystem()->getRealPath($directory);
 
         // Get files without dot directories
         $files = array_values(array_diff(scandir($directory), ['..', '.']));
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php
index 413bae3..dbee374 100644
--- a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php
@@ -9,7 +9,6 @@ use Psr\Log\LoggerInterface;
 use SimpleSAML\Module\accounting\Entities\Activity;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
 use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
-use SimpleSAML\Module\accounting\Entities\ServiceProvider;
 use SimpleSAML\Module\accounting\Entities\User;
 use SimpleSAML\Module\accounting\Exceptions\StoreException;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
@@ -83,7 +82,8 @@ class Store extends AbstractStore implements DataStoreInterface
         $this->repository->insertAuthenticationEvent(
             $idpSpUserVersionId,
             $authenticationEvent->getHappenedAt(),
-            $authenticationEvent->getState()->getClientIpAddress()
+            $authenticationEvent->getState()->getClientIpAddress(),
+            $authenticationEvent->getState()->getAuthenticationProtocol()->getDesignation()
         );
     }
 
@@ -312,13 +312,13 @@ class Store extends AbstractStore implements DataStoreInterface
     {
         $userIdentifierAttributeName = $this->moduleConfiguration->getUserIdAttributeName();
 
-        $userIdentifierValue = $hashDecoratedState->getState()->getAttributeValue($userIdentifierAttributeName);
+        $userIdentifierValue = $hashDecoratedState->getState()->getFirstAttributeValue($userIdentifierAttributeName);
         if ($userIdentifierValue === null) {
             $message = sprintf('Attributes do not contain user ID attribute %s.', $userIdentifierAttributeName);
             throw new UnexpectedValueException($message);
         }
 
-        $userIdentifierValueHashSha256 = $this->helpersManager->getHashHelper()->getSha256($userIdentifierValue);
+        $userIdentifierValueHashSha256 = $this->helpersManager->getHash()->getSha256($userIdentifierValue);
 
         // Check if it already exists.
         try {
@@ -492,7 +492,9 @@ class Store extends AbstractStore implements DataStoreInterface
             foreach ($results as $result) {
                 $rawConnectedServiceProvider = new RawConnectedServiceProvider($result, $databasePlatform);
 
-                $serviceProvider = new ServiceProvider($rawConnectedServiceProvider->getServiceProviderMetadata());
+                $serviceProvider = $this->helpersManager
+                    ->getProviderResolver()
+                    ->forServiceFromMetadataArray($rawConnectedServiceProvider->getServiceProviderMetadata());
                 $user = new User($rawConnectedServiceProvider->getUserAttributes());
 
                 $connectedServiceProviderBag->addOrReplace(
@@ -534,7 +536,9 @@ class Store extends AbstractStore implements DataStoreInterface
             /** @var array $result */
             foreach ($results as $result) {
                 $rawActivity = new RawActivity($result, $this->connection->dbal()->getDatabasePlatform());
-                $serviceProvider = new ServiceProvider($rawActivity->getServiceProviderMetadata());
+                $serviceProvider = $this->helpersManager
+                    ->getProviderResolver()
+                    ->forServiceFromMetadataArray($rawActivity->getServiceProviderMetadata());
                 $user = new User($rawActivity->getUserAttributes());
 
                 $activityBag->add(
@@ -542,7 +546,8 @@ class Store extends AbstractStore implements DataStoreInterface
                         $serviceProvider,
                         $user,
                         $rawActivity->getHappenedAt(),
-                        $rawActivity->getClientIpAddress()
+                        $rawActivity->getClientIpAddress(),
+                        $rawActivity->getAuthenticationProtocolDesignation()
                     )
                 );
             }
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php
index 6811a67..07c60cf 100644
--- a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php
@@ -4,12 +4,12 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
 
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Interfaces\StateInterface;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
 
 class HashDecoratedState
 {
-    protected State $state;
+    protected StateInterface $state;
     protected HelpersManager $helpersManager;
 
     protected string $identityProviderEntityIdHashSha256;
@@ -18,29 +18,26 @@ class HashDecoratedState
     protected string $serviceProviderMetadataArrayHashSha256;
     protected string $attributesArrayHashSha256;
 
-    public function __construct(State $state, HelpersManager $helpersManager = null)
+    public function __construct(StateInterface $state, HelpersManager $helpersManager = null)
     {
         $this->state = $state;
         $this->helpersManager = $helpersManager ?? new HelpersManager();
 
-        $this->identityProviderEntityIdHashSha256 = $this->helpersManager->getHashHelper()
+        $this->identityProviderEntityIdHashSha256 = $this->helpersManager->getHash()
             ->getSha256($state->getIdentityProviderEntityId());
-        $this->identityProviderMetadataArrayHashSha256 = $this->helpersManager->getHashHelper()
+        $this->identityProviderMetadataArrayHashSha256 = $this->helpersManager->getHash()
             ->getSha256ForArray($state->getIdentityProviderMetadata());
 
-        $this->serviceProviderEntityIdHashSha256 = $this->helpersManager->getHashHelper()
+        $this->serviceProviderEntityIdHashSha256 = $this->helpersManager->getHash()
             ->getSha256($state->getServiceProviderEntityId());
-        $this->serviceProviderMetadataArrayHashSha256 = $this->helpersManager->getHashHelper()
+        $this->serviceProviderMetadataArrayHashSha256 = $this->helpersManager->getHash()
             ->getSha256ForArray($state->getServiceProviderMetadata());
 
-        $this->attributesArrayHashSha256 = $this->helpersManager->getHashHelper()
+        $this->attributesArrayHashSha256 = $this->helpersManager->getHash()
             ->getSha256ForArray($state->getAttributes());
     }
 
-    /**
-     * @return State
-     */
-    public function getState(): State
+    public function getState(): StateInterface
     {
         return $this->state;
     }
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php
index b465f7d..65940b5 100644
--- a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php
@@ -44,6 +44,10 @@ class Version20220801000700CreateAuthenticationEventTable extends AbstractMigrat
                 ->setLength(TableConstants::COLUMN_IP_ADDRESS_LENGTH)
                 ->setNotnull(false);
 
+            $table->addColumn('authentication_protocol_designation', Types::STRING)
+                ->setLength(TableConstants::COLUMN_AUTHENTICATION_PROTOCOL_DESIGNATION_LENGTH)
+                ->setNotnull(false);
+
             $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
 
             $table->setPrimaryKey(['id']);
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php
index 16bc176..b943311 100644
--- a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php
@@ -15,6 +15,7 @@ class RawActivity extends AbstractRawEntity
     protected array $userAttributes;
     protected DateTimeImmutable $happenedAt;
     protected ?string $clientIpAddress;
+    protected ?string $authenticationProtocolDesignation;
 
     public function __construct(array $rawRow, AbstractPlatform $abstractPlatform)
     {
@@ -35,6 +36,11 @@ class RawActivity extends AbstractRawEntity
         $this->clientIpAddress = empty($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS]) ?
             null :
             (string)$rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS];
+
+        $this->authenticationProtocolDesignation =
+            empty($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION]) ?
+            null :
+            (string)$rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION];
     }
 
     /**
@@ -69,6 +75,14 @@ class RawActivity extends AbstractRawEntity
         return $this->clientIpAddress;
     }
 
+    /**
+     * @return string|null
+     */
+    public function getAuthenticationProtocolDesignation(): ?string
+    {
+        return $this->authenticationProtocolDesignation;
+    }
+
     /**
      * @inheritDoc
      */
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php
index 32103e0..239adaf 100644
--- a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php
@@ -76,6 +76,7 @@ class Repository
                 $entityIdHashSha256,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('entityIdHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -120,6 +121,7 @@ class Repository
             $queryBuilder->executeStatement();
         } catch (Throwable $exception) {
             $message = sprintf('Error executing query to insert IdP. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message, compact('entityId', 'entityIdHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -162,6 +164,7 @@ class Repository
                 $metadataHashSha256,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('idpId', 'metadataHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -211,6 +214,7 @@ class Repository
             $queryBuilder->executeStatement();
         } catch (Throwable $exception) {
             $message = sprintf('Error executing query to insert IdP Version. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message, compact('idpId', 'metadataHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -243,6 +247,7 @@ class Repository
                 $entityIdHashSha256,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('entityIdHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -287,6 +292,7 @@ class Repository
             $queryBuilder->executeStatement();
         } catch (Throwable $exception) {
             $message = sprintf('Error executing query to insert SP. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message, compact('entityId', 'entityIdHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -329,6 +335,7 @@ class Repository
                 $metadataHashSha256,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('spId', 'metadataHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -378,6 +385,7 @@ class Repository
             $queryBuilder->executeStatement();
         } catch (Throwable $exception) {
             $message = sprintf('Error executing query to insert SP Version. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message, compact('spId', 'metadataHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -410,6 +418,7 @@ class Repository
                 $identifierHashSha256,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('identifierHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -454,6 +463,7 @@ class Repository
             $queryBuilder->executeStatement();
         } catch (Throwable $exception) {
             $message = sprintf('Error executing query to insert user. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message, compact('identifier', 'identifierHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -496,6 +506,7 @@ class Repository
                 $attributesHashSha256,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('userId', 'attributesHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -548,6 +559,7 @@ class Repository
                 'Error executing query to insert user version. Error was: %s.',
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('userId', 'attributesHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -596,6 +608,7 @@ class Repository
                 $userVersionId,
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('idpVersionId', 'spVersionId', 'userVersionId'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -648,6 +661,7 @@ class Repository
                 'Error executing query to insert IdpSpUserVersion. Error was: %s.',
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('idpVersionId', 'spVersionId', 'userVersionId'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -656,9 +670,10 @@ class Repository
      * @throws StoreException
      */
     public function insertAuthenticationEvent(
-        int $IdpSpUserVersionId,
+        int $idpSpUserVersionId,
         DateTimeImmutable $happenedAt,
         string $clientIpAddress = null,
+        string $authenticationProtocolDesignation = null,
         DateTimeImmutable $createdAt = null
     ): void {
         try {
@@ -675,6 +690,9 @@ class Repository
                             TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS => ':' .
                             TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION =>
+                            ':' .
+                            TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT => ':' .
                             TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT,
                     ]
@@ -682,9 +700,11 @@ class Repository
                 ->setParameters(
                     [
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID =>
-                            $IdpSpUserVersionId,
+                            $idpSpUserVersionId,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT => $happenedAt,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS => $clientIpAddress,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION =>
+                            $authenticationProtocolDesignation,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT => $createdAt,
                     ],
                     [
@@ -694,6 +714,8 @@ class Repository
                             Types::DATETIMETZ_IMMUTABLE,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS =>
                             Types::STRING,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION =>
+                            Types::STRING,
                         TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT =>
                             Types::DATETIMETZ_IMMUTABLE,
                     ]
@@ -705,6 +727,7 @@ class Repository
                 'Error executing query to insert AuthenticationEvent. Error was: %s.',
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('idpSpUserVersionId'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -954,6 +977,7 @@ class Repository
                 'Error executing query to get connected organizations. Error was: %s.',
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('userIdentifierHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -973,6 +997,8 @@ class Repository
                 TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT,
                 TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
                 TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS,
+                TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION,
                 //'vsv.metadata AS sp_metadata',
                 TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA .
                 ' AS ' . TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA,
@@ -1067,6 +1093,7 @@ class Repository
                 'Error executing query to get connected organizations. Error was: %s.',
                 $exception->getMessage()
             );
+            $this->logger->error($message, compact('userIdentifierHashSha256'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -1091,6 +1118,7 @@ class Repository
                 'Error executing query to delete old authentication events. Error was: %s.',
                 $exception->getMessage()
             );
+            $this->logger->error($message);
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php
index 532a8c7..df6eb7a 100644
--- a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php
@@ -13,6 +13,7 @@ class TableConstants
     public const COLUMN_ENTITY_ID_LENGTH = 1024;
     public const COLUMN_HASH_SHA265_HEXITS_LENGTH = 64;
     public const COLUMN_IP_ADDRESS_LENGTH = 45;
+    public const COLUMN_AUTHENTICATION_PROTOCOL_DESIGNATION_LENGTH = 16;
 
 
     // Table 'idp'
@@ -84,6 +85,8 @@ class TableConstants
     public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID = 'idp_sp_user_version_id';
     public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT = 'happened_at';
     public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS = 'client_ip_address';
+    public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION =
+        'authentication_protocol_designation';
     public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT = 'created_at';
 
     // Entity 'ConnectedOrganization' (service provider) related.
@@ -99,4 +102,6 @@ class TableConstants
     public const ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES = 'user_attributes';
     public const ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT = 'happened_at';
     public const ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS = 'client_ip_address';
+    public const ENTITY_ACTIVITY_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION =
+        'authentication_protocol_designation';
 }
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/Repository.php b/src/Stores/Jobs/DoctrineDbal/Store/Repository.php
index ac983a7..09a17ff 100644
--- a/src/Stores/Jobs/DoctrineDbal/Store/Repository.php
+++ b/src/Stores/Jobs/DoctrineDbal/Store/Repository.php
@@ -80,6 +80,7 @@ class Repository
             $queryBuilder->executeStatement();
         } catch (Throwable $exception) {
             $message = sprintf('Could not insert job (%s)', $exception->getMessage());
+            $this->logger->error($message);
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
     }
@@ -117,6 +118,7 @@ class Repository
             $row = $result->fetchAssociative();
         } catch (Throwable $exception) {
             $message = 'Error while trying to execute query to get next available job.';
+            $this->logger->error($message);
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
 
@@ -138,6 +140,7 @@ class Repository
             }
         } catch (Throwable $exception) {
             $message = 'Could not create a job instance.';
+            $this->logger->error($message);
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
 
@@ -158,6 +161,7 @@ class Repository
                 );
         } catch (Throwable $exception) {
             $message = sprintf('Error while trying to delete a job with ID %s.', $id);
+            $this->logger->error($message, compact('id'));
             throw new StoreException($message, (int)$exception->getCode(), $exception);
         }
 
diff --git a/src/Stores/Jobs/PhpRedis/RedisStore.php b/src/Stores/Jobs/PhpRedis/RedisStore.php
index 20e6003..0aa6f04 100644
--- a/src/Stores/Jobs/PhpRedis/RedisStore.php
+++ b/src/Stores/Jobs/PhpRedis/RedisStore.php
@@ -156,6 +156,9 @@ class RedisStore extends AbstractStore implements JobsStoreInterface
         return false;
     }
 
+    /**
+     * @codeCoverageIgnore
+     */
     public function runSetup(): void
     {
         // No need for setup.
diff --git a/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php b/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php
index 4a9c431..118ae20 100644
--- a/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php
+++ b/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php
@@ -85,13 +85,13 @@ class Tracker implements AuthenticationDataTrackerInterface, AuthenticationDataP
 
     public function getConnectedServiceProviders(string $userIdentifier): ConnectedServiceProvider\Bag
     {
-        $userIdentifierHashSha256 = $this->helpersManager->getHashHelper()->getSha256($userIdentifier);
+        $userIdentifierHashSha256 = $this->helpersManager->getHash()->getSha256($userIdentifier);
         return $this->dataStore->getConnectedOrganizations($userIdentifierHashSha256);
     }
 
     public function getActivity(string $userIdentifier, int $maxResults, int $firstResult): Activity\Bag
     {
-        $userIdentifierHashSha256 = $this->helpersManager->getHashHelper()->getSha256($userIdentifier);
+        $userIdentifierHashSha256 = $this->helpersManager->getHash()->getSha256($userIdentifier);
         return $this->dataStore->getActivity($userIdentifierHashSha256, $maxResults, $firstResult);
     }
 
diff --git a/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php b/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php
index 762109f..7a58645 100644
--- a/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php
+++ b/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php
@@ -46,7 +46,7 @@ class AuthenticationDataTrackerBuilder
 
             // Build...
             /** @var AuthenticationDataTrackerInterface $store */
-            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()->build(
+            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfiguration()->build(
                 $class,
                 $this->moduleConfiguration,
                 $this->logger
diff --git a/templates/user/activity.twig b/templates/user/activity.twig
index 1ca5ef5..7dae7af 100644
--- a/templates/user/activity.twig
+++ b/templates/user/activity.twig
@@ -32,15 +32,18 @@
                         <img src="{{ asset('css/src/icons/dropdown.svg', 'accounting') }}" alt="Dropdown icon">
                     </label>
                     <div class="dropdown-box">
-                        <strong>{{ 'IP address'|trans }}</strong>
-                        <ul><li>{{ activity.getClientIpAddress|default(' / ') }}</li></ul>
-
-                        <strong>{{ 'Information transfered to service'|trans }}</strong>
+                        <strong>{{ 'Information transfered to service'|trans }}</strong>:
                         {% for name, value in activity.getUser.getAttributes %}
                             <span class="label">
                                 {{ name|trans }}: {{ value|join(', ') }}
                             </span>
                         {% endfor %}
+                        <br><br>
+                        <strong>{{ 'IP address'|trans }}</strong>: {{ activity.getClientIpAddress|default(' / ') }}
+                        <br>
+                        <strong>{{ 'Authentication protocol'|trans }}</strong>:
+                            {{ activity.getAuthenticationProtocolDesignation|default(' / ') }}
+                        <br>
                     </div>
                 </td>
             </tr>
diff --git a/templates/user/connected-organizations.twig b/templates/user/connected-organizations.twig
index 502e97f..6985170 100644
--- a/templates/user/connected-organizations.twig
+++ b/templates/user/connected-organizations.twig
@@ -35,15 +35,6 @@
                             <li>{{ 'Description'|trans }}: {{ connectedServiceProvider.getServiceProvider.getDescription|e|default(' / ') }}</li>
                         </ul>
 
-                        <strong>{{ 'Information transfered to service'|trans }}</strong>
-
-                        {% for name, value in connectedServiceProvider.getUser.getAttributes %}
-                            <span class="label">
-                                {{ name|trans }}: {{ value|join(', ') }}
-                            </span>
-                        {% endfor %}
-
-
                         <strong>{{ 'Login details'|trans }}</strong>
                         <ul>
                             <li>
diff --git a/tests/src/Auth/Process/AccountingTest.php b/tests/src/Auth/Process/AccountingTest.php
index b10d9ad..0bcf385 100644
--- a/tests/src/Auth/Process/AccountingTest.php
+++ b/tests/src/Auth/Process/AccountingTest.php
@@ -21,16 +21,18 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Auth\Process\Accounting
- * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\Event
- * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\State
- * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
- * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
- * @uses   \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
- * @uses   \SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder
- * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
- * @uses   \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
- * @uses   \SimpleSAML\Module\accounting\Helpers\NetworkHelper
- * @uses   \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
+ * @uses \SimpleSAML\Module\accounting\Helpers\AuthenticationEventStateResolver
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
 class AccountingTest extends TestCase
 {
@@ -57,7 +59,7 @@ class AccountingTest extends TestCase
         $this->jobsStoreMock = $this->createMock(Store::class);
         $this->trackerMock = $this->createMock(Tracker::class);
 
-        $this->sampleState = StateArrays::FULL;
+        $this->sampleState = StateArrays::SAML2_FULL;
 
         $this->filterConfig = [];
 
@@ -66,7 +68,6 @@ class AccountingTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(
             Accounting::class,
             new Accounting(
@@ -77,7 +78,6 @@ class AccountingTest extends TestCase
             )
         );
 
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(
             Accounting::class,
             new Accounting(
@@ -112,7 +112,6 @@ class AccountingTest extends TestCase
             ->expects($this->never())
             ->method('build');
 
-        /** @psalm-suppress InvalidArgument */
         (new Accounting(
             $this->filterConfig,
             null,
@@ -147,7 +146,6 @@ class AccountingTest extends TestCase
             ->with($this->equalTo(Tracker::class))
             ->willReturn($this->trackerMock);
 
-        /** @psalm-suppress InvalidArgument */
         (new Accounting(
             $this->filterConfig,
             null,
@@ -166,7 +164,6 @@ class AccountingTest extends TestCase
 
         $this->loggerMock->expects($this->once())->method('error');
 
-        /** @psalm-suppress InvalidArgument */
         (new Accounting(
             $this->filterConfig,
             null,
diff --git a/tests/src/Constants/RawRowResult.php b/tests/src/Constants/RawRowResult.php
index e4224df..2d9f044 100644
--- a/tests/src/Constants/RawRowResult.php
+++ b/tests/src/Constants/RawRowResult.php
@@ -23,5 +23,6 @@ class RawRowResult
         TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA => 'a:9:{s:19:"SingleLogoutService";a:1:{i:0;a:2:{s:7:"Binding";s:50:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";s:8:"Location";s:121:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/singleLogoutService/default-sp";}}s:24:"AssertionConsumerService";a:2:{i:0;a:3:{s:7:"Binding";s:46:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";s:8:"Location";s:126:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp";s:5:"index";i:0;}i:1;a:3:{s:7:"Binding";s:50:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact";s:8:"Location";s:126:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp";s:5:"index";i:1;}}s:8:"contacts";a:1:{i:0;a:3:{s:12:"emailAddress";s:15:"mivanci@srce.hr";s:9:"givenName";s:15:"Marko Ivančić";s:11:"contactType";s:9:"technical";}}s:4:"name";a:1:{s:2:"en";s:12:"Test service";}s:11:"description";a:1:{s:2:"en";s:27:"Description of test service";}s:16:"OrganizationName";a:1:{s:2:"en";s:17:"Test organization";}s:8:"entityid";s:114:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp";s:14:"metadata-index";s:114:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp";s:12:"metadata-set";s:16:"saml20-sp-remote";}',
         TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES => 'a:5:{s:33:"urn:oid:0.9.2342.19200300.100.1.1";a:1:{i:0;s:11:"student-uid";}s:32:"urn:oid:1.3.6.1.4.1.5923.1.1.1.1";a:2:{i:0;s:6:"member";i:1;s:7:"student";}s:15:"urn:oid:2.5.4.4";a:1:{i:0;s:10:"student-sn";}s:19:"hrEduPersonUniqueID";a:1:{i:0;s:19:"student@example.org";}s:23:"hrEduPersonPersistentID";a:1:{i:0;s:13:"student123abc";}}',
         TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS => '172.21.0.1',
+        TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION => 'SAML2',
     ];
 }
diff --git a/tests/src/Constants/StateArrays.php b/tests/src/Constants/StateArrays.php
index e18b082..1833f18 100644
--- a/tests/src/Constants/StateArrays.php
+++ b/tests/src/Constants/StateArrays.php
@@ -7,7 +7,7 @@ namespace SimpleSAML\Test\Module\accounting\Constants;
 
 final class StateArrays
 {
-    public const FULL = [
+    public const SAML2_FULL = [
         'Responder' => [0 => '\\SimpleSAML\\Module\\saml\\IdP\\SAML2', 1 => 'sendResponse',],
         '\\SimpleSAML\\Auth\\State.exceptionFunc' => [
             0 => '\\SimpleSAML\\Module\\saml\\IdP\\SAML2',
@@ -131,4 +131,108 @@ final class StateArrays
         ],
         '\\SimpleSAML\\Auth\\ProcessingChain.filters' => [],
     ];
+
+    public const OIDC_FULL = [
+        'Attributes' => [
+            'hrEduPersonUniqueID' => ['testuser@primjer2.hr'],
+            'uid' => ['testuser'],
+            'cn' => ['TestName TestSurname'],
+            'sn' => ['TestSurname', 'TestSurname2'],
+            'givenName' => ['TestName'],
+            'mail' => ['testusermail@primjer.hr', 'testusermail2@primjer.hr'],
+            'hrEduPersonPersistentID' => ['da4294fb4e5746d57ab6ad88d2daf275'],
+            'displayName' => ['testname123'],
+        ],
+        'Authority' => 'example-userpass',
+        'AuthnInstant' => 1677066265,
+        'Expire' => 1677095065,
+        'LogoutHandlers' => [
+            [
+                'SimpleSAML\Module\oidc\Controller\LogoutController',
+                'logoutHandler'
+            ],
+        ],
+        'Oidc' => [
+            'OpenIdProviderMetadata' => [
+                'issuer' => 'http://op.host.internal:8074',
+                'authorization_endpoint' => 'http://op.host.internal:8074/simplesamlphp/module.php/oidc/authorize.php',
+                'token_endpoint' => 'http://op.host.internal:8074/simplesamlphp/module.php/oidc/token.php',
+                'userinfo_endpoint' => 'http://op.host.internal:8074/simplesamlphp/module.php/oidc/userinfo.php',
+                'end_session_endpoint' => 'http://op.host.internal:8074/simplesamlphp/module.php/oidc/logout.php',
+                'jwks_uri' => 'http://op.host.internal:8074/simplesamlphp/module.php/oidc/jwks.php',
+                'scopes_supported' => [
+                    'openid',
+                    'offline_access',
+                    'profile',
+                    'email',
+                    'address',
+                    'phone',
+                ],
+                'response_types_supported' => [
+                    'code',
+                    'token',
+                    'id_token',
+                    'id_token token',
+                ],
+                'subject_types_supported' => [
+                    'public',
+                ],
+                'id_token_signing_alg_values_supported' => [
+                    'RS256',
+                ],
+                'code_challenge_methods_supported' => [
+                    'plain',
+                    'S256',
+                ],
+                'token_endpoint_auth_methods_supported' => [
+                    'client_secret_post',
+                    'client_secret_basic',
+                ],
+                'request_parameter_supported' => false,
+                'grant_types_supported' => [
+                    'authorization_code',
+                    'refresh_token',
+                ],
+                'claims_parameter_supported' => true,
+                'acr_values_supported' => [
+                    '1',
+                    '0',
+                ],
+                'backchannel_logout_supported' => true,
+                'backchannel_logout_session_supported' => true,
+            ],
+            'RelyingPartyMetadata' => [
+                'id' => 'd1ee56b4-5258-4088-a934-66963df2bcd7',
+                'name' => 'Sample RP',
+                'description' => 'Sample Relying Party',
+                'auth_source' => null,
+                'redirect_uri' => [
+                    'http://sp.host.internal:8074/callback.php',
+                ],
+                'scopes' => [
+                    'openid',
+                    'offline_access',
+                    'profile',
+                ],
+                'is_enabled' => true,
+                'is_confidential' => true,
+                'owner' => null,
+                'post_logout_redirect_uri' => [],
+                'backchannel_logout_uri' => 'http://sp.host.internal:8074/logout.php',
+            ],
+            'AuthorizationRequestParameters' => [
+                'response_type' => 'code',
+                'client_id' => 'd1ee56b4-5258-4088-a934-66963df2bcd7',
+                'redirect_uri' => 'http://sp.host.internal:8074/callback.php',
+                'scope' => 'openid offline_access profile',
+            ],
+            'Source' => [
+                'entityid' => 'http://op.host.internal:8074',
+            ],
+            'Destination' => [
+                'entityid' => 'd1ee56b4-5258-4088-a934-66963df2bcd7',
+            ],
+            '\SimpleSAML\Auth\State.restartURL' => 'http://op.host.internal:8074/simplesamlphp/module.php/oidc/authorize.php?response_type=code&client_id=d1ee56b4-5258-4088-a934-66963df2bcd7&redirect_uri=http%3A%2F%2Fsp.host.internal%3A8074%2Fcallback.php&scope=openid+offline_access+profile+&state=MLlISLjJMKunw0ddFv4ROuyam7Qwn6sNyBW5y9Yg&nonce=uh3nJez5y1SSch347j5PkDWEJXvCwqAI1PL1Kgi6',
+        ]
+    ];
 }
diff --git a/tests/src/Entities/Activity/BagTest.php b/tests/src/Entities/Activity/BagTest.php
index 3d43416..752733c 100644
--- a/tests/src/Entities/Activity/BagTest.php
+++ b/tests/src/Entities/Activity/BagTest.php
@@ -20,7 +20,6 @@ class BagTest extends TestCase
 
         $this->assertEmpty($bag->getAll());
 
-        /** @psalm-suppress InvalidArgument */
         $bag->add($activityStub);
 
         $this->assertNotEmpty($bag->getAll());
diff --git a/tests/src/Entities/ActivityTest.php b/tests/src/Entities/ActivityTest.php
index 5199bfe..e04fb5f 100644
--- a/tests/src/Entities/ActivityTest.php
+++ b/tests/src/Entities/ActivityTest.php
@@ -8,7 +8,8 @@ use DateTimeImmutable;
 use PHPUnit\Framework\MockObject\Stub;
 use SimpleSAML\Module\accounting\Entities\Activity;
 use PHPUnit\Framework\TestCase;
-use SimpleSAML\Module\accounting\Entities\ServiceProvider;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
 use SimpleSAML\Module\accounting\Entities\User;
 
 /**
@@ -17,7 +18,7 @@ use SimpleSAML\Module\accounting\Entities\User;
 class ActivityTest extends TestCase
 {
     /**
-     * @var Stub|ServiceProvider
+     * @var Stub|ServiceProviderInterface
      */
     protected $serviceProviderStub;
     /**
@@ -26,28 +27,31 @@ class ActivityTest extends TestCase
     protected $userStub;
     protected DateTimeImmutable $happenedAt;
     protected string $clientIpAddress;
+    protected string $authenticationProtocolDesignation;
 
     public function setUp(): void
     {
-        $this->serviceProviderStub = $this->createStub(ServiceProvider::class);
+        $this->serviceProviderStub = $this->createStub(ServiceProviderInterface::class);
         $this->userStub = $this->createStub(User::class);
         $this->happenedAt = new DateTimeImmutable();
         $this->clientIpAddress = '123.123.123.123';
+        $this->authenticationProtocolDesignation = Saml2::DESIGNATION;
     }
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $activity = new Activity(
             $this->serviceProviderStub,
             $this->userStub,
             $this->happenedAt,
-            $this->clientIpAddress
+            $this->clientIpAddress,
+            $this->authenticationProtocolDesignation
         );
 
         $this->assertSame($this->serviceProviderStub, $activity->getServiceProvider());
         $this->assertSame($this->userStub, $activity->getUser());
         $this->assertSame($this->happenedAt, $activity->getHappenedAt());
         $this->assertSame($this->clientIpAddress, $activity->getClientIpAddress());
+        $this->assertSame($this->authenticationProtocolDesignation, $activity->getAuthenticationProtocolDesignation());
     }
 }
diff --git a/tests/src/Entities/Authentication/Event/JobTest.php b/tests/src/Entities/Authentication/Event/JobTest.php
index 508118e..b0150d7 100644
--- a/tests/src/Entities/Authentication/Event/JobTest.php
+++ b/tests/src/Entities/Authentication/Event/JobTest.php
@@ -7,7 +7,7 @@ namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Event;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event\Job;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
 use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
@@ -16,15 +16,16 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
  * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
- * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
 class JobTest extends TestCase
 {
     public function testCanCreateInstanceWithAuthenticationEventEntity(): void
     {
-        $job = new Job(new Event(new State(StateArrays::FULL)));
+        $job = new Job(new Event(new State\Saml2(StateArrays::SAML2_FULL)));
 
         $this->assertInstanceOf(Event::class, $job->getPayload());
     }
@@ -41,7 +42,7 @@ class JobTest extends TestCase
 
     public function testCanGetProperType(): void
     {
-        $job = new Job(new Event(new State(StateArrays::FULL)));
+        $job = new Job(new Event(new State\Saml2(StateArrays::SAML2_FULL)));
 
         $this->assertSame(Job::class, $job->getType());
     }
diff --git a/tests/src/Entities/Authentication/Event/State/OidcTest.php b/tests/src/Entities/Authentication/Event/State/OidcTest.php
new file mode 100644
index 0000000..4bf21eb
--- /dev/null
+++ b/tests/src/Entities/Authentication/Event/State/OidcTest.php
@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Event\State;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Helpers\Network;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity;
+use SimpleSAML\Module\accounting\Entities\Providers\Service;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Oidc
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ */
+class OidcTest extends TestCase
+{
+    protected const IP_ADDRESS = '123.123.123.123';
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub
+     */
+    protected $networkHelperStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub
+     */
+    protected $helpersManagerStub;
+
+    public function setUp(): void
+    {
+        $this->networkHelperStub = $this->createStub(Network::class);
+        $this->networkHelperStub->method('resolveClientIpAddress')->willReturn(self::IP_ADDRESS);
+        $this->helpersManagerStub = $this->createStub(HelpersManager::class);
+        $this->helpersManagerStub->method('getNetwork')->willReturn($this->networkHelperStub);
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(
+            State\Oidc::class,
+            new State\Oidc(StateArrays::OIDC_FULL, null, $this->helpersManagerStub)
+        );
+    }
+
+    public function testCanResolveIdentityProviderMetadata(): void
+    {
+        $state = new State\Oidc(StateArrays::OIDC_FULL, null, $this->helpersManagerStub);
+
+        $this->assertSame(
+            StateArrays::OIDC_FULL[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA],
+            $state->getIdentityProviderMetadata()
+        );
+
+        $this->assertSame(
+            StateArrays::OIDC_FULL[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA]
+            [Identity\Oidc::METADATA_KEY_ENTITY_ID],
+            $state->getIdentityProviderEntityId()
+        );
+    }
+
+    public function testCanResolveServiceProviderMetadata(): void
+    {
+        $state = new State\Oidc(StateArrays::OIDC_FULL, null, $this->helpersManagerStub);
+
+        $this->assertSame(
+            StateArrays::OIDC_FULL[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA],
+            $state->getIdentityProviderMetadata()
+        );
+
+        $this->assertSame(
+            StateArrays::OIDC_FULL[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA]
+            [Identity\Oidc::METADATA_KEY_ENTITY_ID],
+            $state->getIdentityProviderEntityId()
+        );
+    }
+
+    public function testThrowsIfOidcMetadataNotAvailable(): void
+    {
+        $stateArray = StateArrays::OIDC_FULL;
+        unset($stateArray[State\Oidc::KEY_OIDC]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        (new State\Oidc($stateArray, null, $this->helpersManagerStub));
+    }
+
+    public function testThrowsIfIdentityProviderMetadataNotAvailable(): void
+    {
+        $stateArray = StateArrays::OIDC_FULL;
+        unset($stateArray[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        (new State\Oidc($stateArray, null, $this->helpersManagerStub));
+    }
+
+    public function testThrowsIfIdentityProviderEntityIdNotAvailable(): void
+    {
+        $stateArray = StateArrays::OIDC_FULL;
+        unset(
+            $stateArray[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA]
+                [Identity\Oidc::METADATA_KEY_ENTITY_ID]
+        );
+
+        $this->expectException(UnexpectedValueException::class);
+
+        (new State\Oidc($stateArray, null, $this->helpersManagerStub));
+    }
+
+    public function testThrowsIfServiceProviderMetadataNotAvailable(): void
+    {
+        $stateArray = StateArrays::OIDC_FULL;
+        unset($stateArray[State\Oidc::KEY_OIDC][State\Oidc::KEY_RELYING_PARTY_METADATA]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        (new State\Oidc($stateArray, null, $this->helpersManagerStub));
+    }
+
+    public function testThrowsIfServiceProviderEntityIdNotAvailable(): void
+    {
+        $stateArray = StateArrays::OIDC_FULL;
+        unset(
+            $stateArray[State\Oidc::KEY_OIDC][State\Oidc::KEY_RELYING_PARTY_METADATA]
+            [Service\Oidc::METADATA_KEY_ENTITY_ID]
+        );
+
+        $this->expectException(UnexpectedValueException::class);
+
+        (new State\Oidc($stateArray, null, $this->helpersManagerStub));
+    }
+
+    public function testCanGetAuthenticationProtocol(): void
+    {
+        $this->assertInstanceOf(
+            Oidc::class,
+            (new State\Oidc(StateArrays::OIDC_FULL, null, $this->helpersManagerStub))
+                ->getAuthenticationProtocol()
+        );
+    }
+}
diff --git a/tests/src/Entities/Authentication/StateTest.php b/tests/src/Entities/Authentication/Event/State/Saml2Test.php
similarity index 60%
rename from tests/src/Entities/Authentication/StateTest.php
rename to tests/src/Entities/Authentication/Event/State/Saml2Test.php
index 0965a1e..664dcc7 100644
--- a/tests/src/Entities/Authentication/StateTest.php
+++ b/tests/src/Entities/Authentication/Event/State/Saml2Test.php
@@ -2,77 +2,79 @@
 
 declare(strict_types=1);
 
-namespace SimpleSAML\Test\Module\accounting\Entities\Authentication;
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Event\State;
 
 use DateTimeImmutable;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
 use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractState;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
 use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Entities\Authentication\State
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
-class StateTest extends TestCase
+class Saml2Test extends TestCase
 {
     public function testCanInitializeValidState(): void
     {
-        $state = new State(StateArrays::FULL);
+        $state = new Saml2(StateArrays::SAML2_FULL);
 
-        $this->assertSame($state->getIdentityProviderEntityId(), StateArrays::FULL['Source']['entityid']);
+        $this->assertSame($state->getIdentityProviderEntityId(), StateArrays::SAML2_FULL['Source']['entityid']);
     }
 
     public function testCanResolveIdpEntityId(): void
     {
-        $stateArray = StateArrays::FULL;
-        $state = new State($stateArray);
-        $this->assertSame($state->getIdentityProviderEntityId(), StateArrays::FULL['IdPMetadata']['entityid']);
+        $stateArray = StateArrays::SAML2_FULL;
+        $state = new Saml2($stateArray);
+        $this->assertSame($state->getIdentityProviderEntityId(), StateArrays::SAML2_FULL['IdPMetadata']['entityid']);
 
         $this->expectException(UnexpectedValueException::class);
         unset($stateArray['IdPMetadata']['entityid']);
-        new State($stateArray);
+        new Saml2($stateArray);
     }
 
     public function testCanResolveSpEntityId(): void
     {
-        $stateArray = StateArrays::FULL;
-        $state = new State($stateArray);
-        $this->assertSame($state->getServiceProviderEntityId(), StateArrays::FULL['SPMetadata']['entityid']);
+        $stateArray = StateArrays::SAML2_FULL;
+        $state = new Saml2($stateArray);
+        $this->assertSame($state->getServiceProviderEntityId(), StateArrays::SAML2_FULL['SPMetadata']['entityid']);
 
         $this->expectException(UnexpectedValueException::class);
         unset($stateArray['SPMetadata']['entityid']);
-        new State($stateArray);
+        new Saml2($stateArray);
     }
 
     public function testCanResolveAttributes(): void
     {
-        $state = new State(StateArrays::FULL);
-        $this->assertSame($state->getAttributes(), StateArrays::FULL['Attributes']);
+        $state = new Saml2(StateArrays::SAML2_FULL);
+        $this->assertSame($state->getAttributes(), StateArrays::SAML2_FULL['Attributes']);
     }
 
     public function testCanResolveAccountedClientIpAddress(): void
     {
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
 
-        $state = new State($stateArray);
+        $state = new Saml2($stateArray);
         $this->assertNull($state->getClientIpAddress());
 
         $sampleIp = '123.123.123.123';
-        $stateArray[State::KEY_ACCOUNTING][State::ACCOUNTING_KEY_CLIENT_IP_ADDRESS] = $sampleIp;
+        $stateArray[AbstractState::KEY_ACCOUNTING][AbstractState::ACCOUNTING_KEY_CLIENT_IP_ADDRESS] = $sampleIp;
 
-        $state = new State($stateArray);
+        $state = new Saml2($stateArray);
         $this->assertSame($sampleIp, $state->getClientIpAddress());
     }
 
     public function testReturnsNullIfAuthnInstantNotPresent(): void
     {
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
 
         unset($stateArray['AuthnInstant']);
 
-        $state = new State($stateArray);
+        $state = new Saml2($stateArray);
 
         $this->assertNull($state->getAuthenticationInstant());
     }
@@ -81,109 +83,115 @@ class StateTest extends TestCase
     {
         $this->expectException(UnexpectedValueException::class);
 
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
 
         unset($stateArray['Source'], $stateArray['IdPMetadata']);
 
-        /** @psalm-suppress UnusedMethodCall */
-        (new State($stateArray));
+        (new Saml2($stateArray));
     }
 
     public function testUseSpMetadataForEntityIdIfDestinationNotAvailable(): void
     {
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
 
         unset($stateArray['Destination']);
 
-        $state = new State($stateArray);
+        $state = new Saml2($stateArray);
 
-        $this->assertSame($state->getServiceProviderEntityId(), StateArrays::FULL['SPMetadata']['entityid']);
+        $this->assertSame($state->getServiceProviderEntityId(), StateArrays::SAML2_FULL['SPMetadata']['entityid']);
     }
 
     public function testThrowsOnMissingDestinationEntityId(): void
     {
         $this->expectException(UnexpectedValueException::class);
 
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
 
         unset($stateArray['Destination'], $stateArray['SPMetadata']);
 
-        (new State($stateArray));
+        (new Saml2($stateArray));
     }
 
     public function testThrowsOnInvalidAuthnInstantValue(): void
     {
         $this->expectException(UnexpectedValueException::class);
 
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
         $stateArray['AuthnInstant'] = 'invalid';
 
-        new State($stateArray);
+        new Saml2($stateArray);
     }
 
     public function testThrowsOnMissingAttributes(): void
     {
         $this->expectException(UnexpectedValueException::class);
 
-        $stateArray = StateArrays::FULL;
+        $stateArray = StateArrays::SAML2_FULL;
 
         unset($stateArray['Attributes']);
 
-        /** @psalm-suppress UnusedMethodCall */
-        (new State($stateArray));
+        (new Saml2($stateArray));
     }
 
     public function testCanGetAttributeValue(): void
     {
-        $state = new State(StateArrays::FULL);
+        $state = new Saml2(StateArrays::SAML2_FULL);
 
         $this->assertSame(
-            StateArrays::FULL['Attributes']['hrEduPersonUniqueID'][0],
-            $state->getAttributeValue('hrEduPersonUniqueID')
+            StateArrays::SAML2_FULL['Attributes']['hrEduPersonUniqueID'][0],
+            $state->getFirstAttributeValue('hrEduPersonUniqueID')
         );
 
-        $this->assertNull($state->getAttributeValue('non-existent'));
+        $this->assertNull($state->getFirstAttributeValue('non-existent'));
     }
 
     public function testCanResolveIdpMetadataArray(): void
     {
         // Metadata from 'IdPMetadata'
-        $sampleState = StateArrays::FULL;
-        $state = new State($sampleState);
+        $sampleState = StateArrays::SAML2_FULL;
+        $state = new Saml2($sampleState);
         $this->assertEquals($sampleState['IdPMetadata'], $state->getIdentityProviderMetadata());
 
         // Fallback metadata from 'Source'
         unset($sampleState['IdPMetadata']);
-        $state = new State($sampleState);
+        $state = new Saml2($sampleState);
         $this->assertEquals($sampleState['Source'], $state->getIdentityProviderMetadata());
 
         // Throws on no IdP metadata
         $this->expectException(UnexpectedValueException::class);
         unset($sampleState['Source']);
-        new State($sampleState);
+        new Saml2($sampleState);
     }
 
     public function testCanResolveSpMetadataArray(): void
     {
         // Metadata from 'IdPMetadata'
-        $sampleState = StateArrays::FULL;
-        $state = new State($sampleState);
+        $sampleState = StateArrays::SAML2_FULL;
+        $state = new Saml2($sampleState);
         $this->assertEquals($sampleState['SPMetadata'], $state->getServiceProviderMetadata());
 
         // Fallback metadata from 'Destination'
         unset($sampleState['SPMetadata']);
-        $state = new State($sampleState);
+        $state = new Saml2($sampleState);
         $this->assertEquals($sampleState['Destination'], $state->getServiceProviderMetadata());
 
         // Throws on no SP metadata
         $this->expectException(UnexpectedValueException::class);
         unset($sampleState['Destination']);
-        new State($sampleState);
+        new Saml2($sampleState);
     }
 
     public function testCanGetCreatedAt(): void
     {
-        $state = new State(StateArrays::FULL);
+        $state = new Saml2(StateArrays::SAML2_FULL);
         $this->assertInstanceOf(DateTimeImmutable::class, $state->getCreatedAt());
     }
+
+    public function testCanGetAuthenticationProtocol(): void
+    {
+        $this->assertInstanceOf(
+            \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2::class,
+            (new Saml2(StateArrays::SAML2_FULL))->getAuthenticationProtocol()
+        );
+    }
 }
diff --git a/tests/src/Entities/Authentication/EventTest.php b/tests/src/Entities/Authentication/EventTest.php
index 28929d6..28ef080 100644
--- a/tests/src/Entities/Authentication/EventTest.php
+++ b/tests/src/Entities/Authentication/EventTest.php
@@ -7,13 +7,14 @@ namespace SimpleSAML\Test\Module\accounting\Entities\Authentication;
 use DateTimeImmutable;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Event
- * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
 class EventTest extends TestCase
@@ -21,12 +22,12 @@ class EventTest extends TestCase
     public function testCanGetState(): void
     {
         $dateTime = new DateTimeImmutable();
-        $authenticationEvent = new Event(new State(StateArrays::FULL), $dateTime);
+        $authenticationEvent = new Event(new State\Saml2(StateArrays::SAML2_FULL), $dateTime);
 
-        $this->assertInstanceOf(State::class, $authenticationEvent->getState());
+        $this->assertInstanceOf(State\Saml2::class, $authenticationEvent->getState());
 
         $this->assertSame(
-            StateArrays::FULL['Source']['entityid'],
+            StateArrays::SAML2_FULL['Source']['entityid'],
             $authenticationEvent->getState()->getIdentityProviderEntityId()
         );
 
diff --git a/tests/src/Entities/Authentication/Protocol/BagTest.php b/tests/src/Entities/Authentication/Protocol/BagTest.php
new file mode 100644
index 0000000..0cd513e
--- /dev/null
+++ b/tests/src/Entities/Authentication/Protocol/BagTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Protocol;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Bag;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Bag
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc
+ */
+class BagTest extends TestCase
+{
+    public function testCanCreateInstance(): void
+    {
+        $bag = new Bag();
+
+        $this->assertInstanceOf(Bag::class, $bag);
+    }
+
+    public function testCanGetById(): void
+    {
+        $bag = new Bag();
+
+        $this->assertInstanceOf(Saml2::class, $bag->getById(Saml2::ID));
+        $this->assertInstanceOf(Oidc::class, $bag->getById(Oidc::ID));
+    }
+
+    public function testCagGetAll(): void
+    {
+        $bag = new Bag();
+
+        foreach ($bag->getAll() as $protocol) {
+            $this->assertInstanceOf(AuthenticationProtocolInterface::class, $protocol);
+        }
+    }
+}
diff --git a/tests/src/Entities/Authentication/Protocol/OidcTest.php b/tests/src/Entities/Authentication/Protocol/OidcTest.php
new file mode 100644
index 0000000..c4ce895
--- /dev/null
+++ b/tests/src/Entities/Authentication/Protocol/OidcTest.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Protocol;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc
+ */
+class OidcTest extends TestCase
+{
+    public function testCanGetDesignation(): void
+    {
+        // This should never change.
+        $this->assertSame('OIDC', (new Oidc())->getDesignation());
+    }
+
+    public function testCanGetId(): void
+    {
+        $this->assertSame(2, (new Oidc())->getId());
+    }
+}
diff --git a/tests/src/Entities/Authentication/Protocol/Saml2Test.php b/tests/src/Entities/Authentication/Protocol/Saml2Test.php
new file mode 100644
index 0000000..2167d63
--- /dev/null
+++ b/tests/src/Entities/Authentication/Protocol/Saml2Test.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Protocol;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2
+ */
+class Saml2Test extends TestCase
+{
+    public function testCanGetDesignation(): void
+    {
+        // This should never change.
+        $this->assertSame('SAML2', (new Saml2())->getDesignation());
+    }
+
+    public function testCanGetId(): void
+    {
+        // This should never change.
+        $this->assertSame(1, (new Saml2())->getId());
+    }
+}
diff --git a/tests/src/Entities/Bases/AbstractProviderTest.php b/tests/src/Entities/Bases/AbstractProviderTest.php
index f888d23..5eac3d8 100644
--- a/tests/src/Entities/Bases/AbstractProviderTest.php
+++ b/tests/src/Entities/Bases/AbstractProviderTest.php
@@ -6,71 +6,66 @@ namespace SimpleSAML\Test\Module\accounting\Entities\Bases;
 
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
 use PHPUnit\Framework\TestCase;
-use SimpleSAML\Module\accounting\Entities\IdentityProvider;
-use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
- * @uses \SimpleSAML\Module\accounting\Entities\IdentityProvider
  */
 class AbstractProviderTest extends TestCase
 {
-    /**
-     * @var array
-     */
     protected array $metadata;
+    protected AbstractProvider $sampleProvider;
 
     public function setUp(): void
     {
         $this->metadata = [
-            AbstractProvider::METADATA_KEY_ENTITY_ID => 'http//example.org/idp',
-            AbstractProvider::METADATA_KEY_NAME => [
+            'entityid' => 'http//example.org/idp',
+            'name' => [
                 'en' => 'Example service',
             ],
-            AbstractProvider::METADATA_KEY_DESCRIPTION => [
+            'description' => [
                 'en' => 'Example description'
             ],
         ];
+
+        $this->sampleProvider = $this->prepareSampleProvider($this->metadata);
     }
 
-    /**
-     * @psalm-suppress MixedArrayAccess
-     */
     public function testCanCreateInstance(): void
     {
-        $identityProvider = new IdentityProvider($this->metadata);
+        $this->assertInstanceOf(AbstractProvider::class, $this->sampleProvider);
 
-        $this->assertSame($this->metadata, $identityProvider->getMetadata());
+        $this->assertSame($this->metadata, $this->sampleProvider->getMetadata());
         $this->assertSame(
-            $this->metadata[AbstractProvider::METADATA_KEY_ENTITY_ID],
-            $identityProvider->getEntityId()
+            $this->metadata['entityid'],
+            $this->sampleProvider->getEntityId()
         );
         $this->assertSame(
-            $this->metadata[AbstractProvider::METADATA_KEY_NAME]['en'],
-            $identityProvider->getName()
+            $this->metadata['name']['en'],
+            $this->sampleProvider->getName()
         );
         $this->assertSame(
-            $this->metadata[AbstractProvider::METADATA_KEY_DESCRIPTION]['en'],
-            $identityProvider->getDescription()
+            $this->metadata['description']['en'],
+            $this->sampleProvider->getDescription()
         );
     }
 
     public function testCanResolveNonLocalizedString(): void
     {
         $metadata = $this->metadata;
-        $metadata[AbstractProvider::METADATA_KEY_DESCRIPTION] = 'Non localized description.';
+        $metadata['description'] = 'Non localized description.';
 
-        $identityProvider = new IdentityProvider($metadata);
+        $identityProvider = $this->prepareSampleProvider($metadata);
 
-        $this->assertSame($metadata[AbstractProvider::METADATA_KEY_DESCRIPTION], $identityProvider->getDescription());
+        $this->assertSame($metadata['description'], $identityProvider->getDescription());
     }
 
     public function testInvalidLocalizedDataResolvesToNull(): void
     {
         $metadata = $this->metadata;
-        $metadata[AbstractProvider::METADATA_KEY_DESCRIPTION] = false;
+        $metadata['description'] = false;
 
-        $identityProvider = new IdentityProvider($metadata);
+        $identityProvider = $this->prepareSampleProvider($metadata);
 
         $this->assertNull($identityProvider->getDescription());
     }
@@ -78,18 +73,29 @@ class AbstractProviderTest extends TestCase
     public function testReturnsNullIfNameNotAvailable(): void
     {
         $metadata = $this->metadata;
-        unset($metadata[AbstractProvider::METADATA_KEY_NAME]);
+        unset($metadata['name']);
 
-        $identityProvider = new IdentityProvider($metadata);
+        $identityProvider = $this->prepareSampleProvider($metadata);
         $this->assertNull($identityProvider->getName());
     }
 
-    public function testThrowsIfEntityIdNotAvailable(): void
+    protected function prepareSampleProvider(array $metadata): AbstractProvider
     {
-        $metadata = $this->metadata;
-        unset($metadata[AbstractProvider::METADATA_KEY_ENTITY_ID]);
-
-        $this->expectException(UnexpectedValueException::class);
-        new IdentityProvider($metadata);
+        return new class ($metadata) extends AbstractProvider {
+            public function getName(string $locale = 'en'): ?string
+            {
+                return $this->resolveOptionallyLocalizedString('name', $locale);
+            }
+
+            public function getDescription(string $locale = 'en'): ?string
+            {
+                return $this->resolveOptionallyLocalizedString('description', $locale);
+            }
+
+            protected function resolveEntityId(): string
+            {
+                return (string)($this->metadata['entityid'] ?? 'N/A');
+            }
+        };
     }
 }
diff --git a/tests/src/Entities/Bases/AbstractStateTest.php b/tests/src/Entities/Bases/AbstractStateTest.php
new file mode 100644
index 0000000..95b3cd2
--- /dev/null
+++ b/tests/src/Entities/Bases/AbstractStateTest.php
@@ -0,0 +1,200 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Bases;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractState;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Helpers\Network;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ */
+class AbstractStateTest extends TestCase
+{
+    protected const IP_ADDRESS = '123.123.123.123';
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub
+     */
+    protected $networkHelperStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub
+     */
+    protected $helpersManagerStub;
+
+    public function setUp(): void
+    {
+        $this->networkHelperStub = $this->createStub(Network::class);
+        $this->networkHelperStub->method('resolveClientIpAddress')->willReturn(self::IP_ADDRESS);
+        $this->helpersManagerStub = $this->createStub(HelpersManager::class);
+        $this->helpersManagerStub->method('getNetwork')->willReturn($this->networkHelperStub);
+    }
+
+    public function testCanGetAttributes(): void
+    {
+        $this->assertSame(
+            StateArrays::SAML2_FULL[AbstractState::KEY_ATTRIBUTES],
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)->getAttributes()
+        );
+    }
+
+    public function testCanGetAttributeValue(): void
+    {
+        $attributeName = 'urn:oid:2.5.4.4';
+
+        $this->assertSame(
+            StateArrays::SAML2_FULL[AbstractState::KEY_ATTRIBUTES][$attributeName],
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)
+                ->getAttributeValue($attributeName)
+        );
+    }
+
+    public function testReturnsNullForNonExistentAttribute(): void
+    {
+        $this->assertNull(
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)
+                ->getAttributeValue('invalid')
+        );
+
+        $this->assertNull(
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)
+                ->getFirstAttributeValue('invalid')
+        );
+    }
+
+    public function testCanGetFirstAttributeValue(): void
+    {
+        $attributeName = 'urn:oid:2.5.4.4';
+
+        $this->assertSame(
+            StateArrays::SAML2_FULL[AbstractState::KEY_ATTRIBUTES][$attributeName][0],
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)
+                ->getFirstAttributeValue($attributeName)
+        );
+    }
+
+    public function testThrowsIfNoAttributes(): void
+    {
+        $stateArray = StateArrays::SAML2_FULL;
+        unset($stateArray[AbstractState::KEY_ATTRIBUTES]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        $this->getSampleInstance($stateArray, null, $this->helpersManagerStub);
+    }
+
+    public function testCanGetClientIpAddressFromNetwork(): void
+    {
+        $this->assertSame(
+            self::IP_ADDRESS,
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)->getClientIpAddress()
+        );
+    }
+
+    public function testCanGetClientIpAddressFromState(): void
+    {
+        $networkHelperMock = $this->createMock(Network::class);
+        $networkHelperMock->method('resolveClientIpAddress')
+            ->with($this->isType('string'))
+            ->will($this->returnArgument(0));
+
+        $helpersManagerStub = $this->createStub(HelpersManager::class);
+        $helpersManagerStub->method('getNetwork')->willReturn($networkHelperMock);
+
+        $stateIp = '111.111.111.111';
+        $stateArray = StateArrays::SAML2_FULL;
+        $stateArray[AbstractState::KEY_ACCOUNTING][AbstractState::ACCOUNTING_KEY_CLIENT_IP_ADDRESS] = $stateIp;
+        $this->assertSame(
+            $stateIp,
+            $this->getSampleInstance($stateArray, null, $helpersManagerStub)->getClientIpAddress()
+        );
+    }
+
+    public function testCanGetAuthenticationInstant(): void
+    {
+        $this->assertInstanceOf(
+            \DateTimeImmutable::class,
+            $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub)
+                ->getAuthenticationInstant()
+        );
+    }
+
+    public function testAuthenticationInstantIsNullIfNotInState(): void
+    {
+        $stateArray = StateArrays::SAML2_FULL;
+        unset($stateArray[AbstractState::KEY_AUTHENTICATION_INSTANT]);
+
+        $this->assertNull(
+            $this->getSampleInstance($stateArray, null, $this->helpersManagerStub)->getAuthenticationInstant()
+        );
+    }
+
+    public function testThrowsForInvalidAuthenticationInstant(): void
+    {
+        $stateArray = StateArrays::SAML2_FULL;
+        $stateArray[AbstractState::KEY_AUTHENTICATION_INSTANT] = 'invalid';
+
+        $this->expectException(UnexpectedValueException::class);
+
+        $this->getSampleInstance($stateArray, null, $this->helpersManagerStub)->getAuthenticationInstant();
+    }
+
+    public function testCanGetResolvedProperties(): void
+    {
+        $instance = $this->getSampleInstance(StateArrays::SAML2_FULL, null, $this->helpersManagerStub);
+        $this->assertIsString($instance->getIdentityProviderEntityId());
+        $this->assertIsString($instance->getServiceProviderEntityId());
+        $this->assertInstanceOf(\DateTimeImmutable::class, $instance->getCreatedAt());
+        $this->assertIsArray($instance->getIdentityProviderMetadata());
+        $this->assertIsArray($instance->getServiceProviderMetadata());
+    }
+
+    protected function getSampleInstance(
+        array $state,
+        \DateTimeImmutable $createdAt = null,
+        HelpersManager $helpersManager = null
+    ): AbstractState {
+        return new class ($state, $createdAt, $helpersManager) extends AbstractState {
+            protected function resolveIdentityProviderMetadata(array $state): array
+            {
+                return []; // Abstract, will not test here.
+            }
+
+            protected function resolveIdentityProviderEntityId(): string
+            {
+                return ''; // Abstract, will not test here.
+            }
+
+            protected function resolveServiceProviderMetadata(array $state): array
+            {
+                return []; // Abstract, will not test here.
+            }
+
+            protected function resolveServiceProviderEntityId(): string
+            {
+                return ''; // Abstract, will not test here.
+            }
+
+            public function getAuthenticationProtocol(): AuthenticationProtocolInterface
+            {
+                // Abstract, will not test here.
+                return new class () implements AuthenticationProtocolInterface {
+                    public function getDesignation(): string
+                    {
+                        return '';
+                    }
+
+                    public function getId(): int
+                    {
+                        return 0;
+                    }
+                };
+            }
+        };
+    }
+}
diff --git a/tests/src/Entities/ConnectedServiceProviderTest.php b/tests/src/Entities/ConnectedServiceProviderTest.php
index f5df43b..6dcee02 100644
--- a/tests/src/Entities/ConnectedServiceProviderTest.php
+++ b/tests/src/Entities/ConnectedServiceProviderTest.php
@@ -8,7 +8,7 @@ use DateTimeImmutable;
 use PHPUnit\Framework\MockObject\Stub;
 use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
 use PHPUnit\Framework\TestCase;
-use SimpleSAML\Module\accounting\Entities\ServiceProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
 use SimpleSAML\Module\accounting\Entities\User;
 
 /**
@@ -17,11 +17,11 @@ use SimpleSAML\Module\accounting\Entities\User;
 class ConnectedServiceProviderTest extends TestCase
 {
     /**
-     * @var Stub|ServiceProvider
+     * @var Stub
      */
     protected $serviceProviderStub;
     /**
-     * @var Stub|User
+     * @var Stub
      */
     protected $userStub;
     protected DateTimeImmutable $dateTime;
@@ -29,7 +29,7 @@ class ConnectedServiceProviderTest extends TestCase
 
     public function setUp(): void
     {
-        $this->serviceProviderStub = $this->createStub(ServiceProvider::class);
+        $this->serviceProviderStub = $this->createStub(ServiceProviderInterface::class);
         $this->userStub = $this->createStub(User::class);
         $this->dateTime = new DateTimeImmutable();
         $this->numberOfAuthentications = 1;
@@ -37,7 +37,6 @@ class ConnectedServiceProviderTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $connectedServiceProvider = new ConnectedServiceProvider(
             $this->serviceProviderStub,
             $this->numberOfAuthentications,
diff --git a/tests/src/Entities/IdentityProviderTest.php b/tests/src/Entities/IdentityProviderTest.php
deleted file mode 100644
index 401c926..0000000
--- a/tests/src/Entities/IdentityProviderTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Test\Module\accounting\Entities;
-
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
-use SimpleSAML\Module\accounting\Entities\IdentityProvider;
-use PHPUnit\Framework\TestCase;
-
-/**
- * @covers \SimpleSAML\Module\accounting\Entities\IdentityProvider
- * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
- */
-class IdentityProviderTest extends TestCase
-{
-    /**
-     * @var string[]
-     */
-    protected array $metadata;
-
-    public function setUp(): void
-    {
-        $this->metadata = [
-            AbstractProvider::METADATA_KEY_ENTITY_ID => 'http//example.org/idp'
-        ];
-    }
-
-    public function testCanCreateInstance(): void
-    {
-        $identityProvider = new IdentityProvider($this->metadata);
-        $this->assertSame($this->metadata, $identityProvider->getMetadata());
-    }
-}
diff --git a/tests/src/Entities/Providers/Identity/OidcTest.php b/tests/src/Entities/Providers/Identity/OidcTest.php
new file mode 100644
index 0000000..450a0cd
--- /dev/null
+++ b/tests/src/Entities/Providers/Identity/OidcTest.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Providers\Identity;
+
+use SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class OidcTest extends TestCase
+{
+    /**
+     * @var string[]
+     */
+    protected array $metadata;
+
+    protected function setUp(): void
+    {
+        $this->metadata = [
+            Oidc::METADATA_KEY_ENTITY_ID => 'sample-issuer',
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $identityProvider = new Oidc($this->metadata);
+        $this->assertSame($identityProvider->getMetadata(), $this->metadata);
+        $this->assertSame($identityProvider->getEntityId(), $this->metadata[Oidc::METADATA_KEY_ENTITY_ID]);
+        $this->assertSame($identityProvider->getName(), null);
+        $this->assertSame($identityProvider->getDescription(), null);
+    }
+
+    public function testThrowsIfEntityIdNotSet(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[Oidc::METADATA_KEY_ENTITY_ID]);
+
+        $this->expectException(MetadataException::class);
+
+        new Oidc($metadata);
+    }
+}
diff --git a/tests/src/Entities/Providers/Identity/Saml2Test.php b/tests/src/Entities/Providers/Identity/Saml2Test.php
new file mode 100644
index 0000000..f2214d8
--- /dev/null
+++ b/tests/src/Entities/Providers/Identity/Saml2Test.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Providers\Identity;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class Saml2Test extends TestCase
+{
+    /**
+     * @var string[]
+     */
+    protected array $metadata;
+
+    public function setUp(): void
+    {
+        $this->metadata = [
+            Saml2::METADATA_KEY_ENTITY_ID => 'http//example.org/idp',
+            Saml2::METADATA_KEY_NAME => 'Sample IdP',
+            Saml2::METADATA_KEY_DESCRIPTION => 'Sample description.',
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $identityProvider = new Saml2($this->metadata);
+        $this->assertSame($this->metadata, $identityProvider->getMetadata());
+        $this->assertSame($this->metadata[Saml2::METADATA_KEY_NAME], $identityProvider->getName());
+        $this->assertSame($this->metadata[Saml2::METADATA_KEY_DESCRIPTION], $identityProvider->getDescription());
+    }
+
+    public function testThrowsIfEntityIdNotSet(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[Saml2::METADATA_KEY_ENTITY_ID]);
+
+        $this->expectException(MetadataException::class);
+
+        new Saml2($metadata);
+    }
+}
diff --git a/tests/src/Entities/Providers/Service/OidcTest.php b/tests/src/Entities/Providers/Service/OidcTest.php
new file mode 100644
index 0000000..4827e5c
--- /dev/null
+++ b/tests/src/Entities/Providers/Service/OidcTest.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Providers\Service;
+
+use SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class OidcTest extends TestCase
+{
+    /**
+     * @var string[]
+     */
+    protected array $metadata;
+
+    protected function setUp(): void
+    {
+        $this->metadata = [
+            Oidc::METADATA_KEY_ENTITY_ID => 'sample-rp',
+            Oidc::METADATA_KEY_NAME => 'Sample Name',
+            Oidc::METADATA_KEY_DESCRIPTION => 'Sample description.',
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $serviceProvider = new Oidc($this->metadata);
+        $this->assertSame($this->metadata, $serviceProvider->getMetadata());
+        $this->assertSame($this->metadata[Oidc::METADATA_KEY_ENTITY_ID], $serviceProvider->getEntityId());
+        $this->assertSame($this->metadata[Oidc::METADATA_KEY_NAME], $serviceProvider->getName());
+        $this->assertSame($this->metadata[Oidc::METADATA_KEY_DESCRIPTION], $serviceProvider->getDescription());
+    }
+
+    public function testThrowsIfEntityIdNotSet(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[Oidc::METADATA_KEY_ENTITY_ID]);
+
+        $this->expectException(MetadataException::class);
+
+        new Oidc($metadata);
+    }
+}
diff --git a/tests/src/Entities/Providers/Service/Saml2Test.php b/tests/src/Entities/Providers/Service/Saml2Test.php
new file mode 100644
index 0000000..f8565c1
--- /dev/null
+++ b/tests/src/Entities/Providers/Service/Saml2Test.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Providers\Service;
+
+use SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class Saml2Test extends TestCase
+{
+    protected array $metadata;
+
+    protected function setUp(): void
+    {
+        $this->metadata = [
+            Saml2::METADATA_KEY_ENTITY_ID => 'sample-serivice',
+            Saml2::METADATA_KEY_NAME => 'Sample Name',
+            Saml2::METADATA_KEY_DESCRIPTION => 'Sample description.',
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $serviceProvider = new Saml2($this->metadata);
+        $this->assertSame($this->metadata, $serviceProvider->getMetadata());
+        $this->assertSame($this->metadata[Saml2::METADATA_KEY_ENTITY_ID], $serviceProvider->getEntityId());
+        $this->assertSame($this->metadata[Saml2::METADATA_KEY_NAME], $serviceProvider->getName());
+        $this->assertSame($this->metadata[Saml2::METADATA_KEY_DESCRIPTION], $serviceProvider->getDescription());
+    }
+
+    public function testThrowsIfEntityIdNotSet(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[Saml2::METADATA_KEY_ENTITY_ID]);
+
+        $this->expectException(MetadataException::class);
+
+        new Saml2($metadata);
+    }
+}
diff --git a/tests/src/Entities/ServiceProviderTest.php b/tests/src/Entities/ServiceProviderTest.php
deleted file mode 100644
index d414b1c..0000000
--- a/tests/src/Entities/ServiceProviderTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Test\Module\accounting\Entities;
-
-use SimpleSAML\Module\accounting\Entities\ServiceProvider;
-use PHPUnit\Framework\TestCase;
-
-/**
- * @covers \SimpleSAML\Module\accounting\Entities\ServiceProvider
- * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
- */
-class ServiceProviderTest extends TestCase
-{
-    /**
-     * @var string[]
-     */
-    protected array $metadata;
-
-    public function setUp(): void
-    {
-        $this->metadata = [
-            'entityid' => 'http//example.org'
-        ];
-    }
-
-    public function testCanCreateInstance(): void
-    {
-        $serviceProvider = new ServiceProvider($this->metadata);
-        $this->assertSame($this->metadata, $serviceProvider->getMetadata());
-    }
-}
diff --git a/tests/src/Helpers/ArrayHelperTest.php b/tests/src/Helpers/ArrayTest.php
similarity index 70%
rename from tests/src/Helpers/ArrayHelperTest.php
rename to tests/src/Helpers/ArrayTest.php
index 5d7c639..0aeb6df 100644
--- a/tests/src/Helpers/ArrayHelperTest.php
+++ b/tests/src/Helpers/ArrayTest.php
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Test\Module\accounting\Helpers;
 
-use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
+use SimpleSAML\Module\accounting\Helpers\Arr;
 use PHPUnit\Framework\TestCase;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\Arr
  */
-class ArrayHelperTest extends TestCase
+class ArrayTest extends TestCase
 {
     public function testCanRecursivelySortByKey(): void
     {
@@ -26,7 +26,7 @@ class ArrayHelperTest extends TestCase
 
         $this->assertNotSame($unsorted, $sorted);
 
-        (new ArrayHelper())->recursivelySortByKey($unsorted);
+        (new Arr())->recursivelySortByKey($unsorted);
 
         $this->assertSame($unsorted, $sorted);
     }
diff --git a/tests/src/Helpers/AttributesHelperTest.php b/tests/src/Helpers/AttributesTest.php
similarity index 92%
rename from tests/src/Helpers/AttributesHelperTest.php
rename to tests/src/Helpers/AttributesTest.php
index c94e6fc..82b97eb 100644
--- a/tests/src/Helpers/AttributesHelperTest.php
+++ b/tests/src/Helpers/AttributesTest.php
@@ -9,11 +9,11 @@ use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\AttributesHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\Attributes
  * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
-class AttributesHelperTest extends TestCase
+class AttributesTest extends TestCase
 {
     /**
      * @var string $sspBaseDir Simulated SSP base directory.
@@ -38,7 +38,7 @@ class AttributesHelperTest extends TestCase
 
     public function testCanLoadAttributeMaps(): void
     {
-        $fullAttributeMap = $this->helpersManager->getAttributesHelper()
+        $fullAttributeMap = $this->helpersManager->getAttributes()
             ->getMergedAttributeMapForFiles($this->sspBaseDir, $this->mapFiles);
 
         $this->assertArrayHasKey('mobile', $fullAttributeMap);
@@ -47,7 +47,7 @@ class AttributesHelperTest extends TestCase
 
     public function testIgnoresNonExistentMaps(): void
     {
-        $fullAttributeMap = $this->helpersManager->getAttributesHelper()
+        $fullAttributeMap = $this->helpersManager->getAttributes()
             ->getMergedAttributeMapForFiles($this->sspBaseDir, ['invalid.php']);
 
         $this->assertEmpty($fullAttributeMap);
diff --git a/tests/src/Helpers/AuthenticationEventStateResolverTest.php b/tests/src/Helpers/AuthenticationEventStateResolverTest.php
new file mode 100644
index 0000000..4799a89
--- /dev/null
+++ b/tests/src/Helpers/AuthenticationEventStateResolverTest.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Oidc;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractState;
+use SimpleSAML\Module\accounting\Exceptions\StateException;
+use SimpleSAML\Module\accounting\Helpers\AuthenticationEventStateResolver;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\AuthenticationEventStateResolver
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Oidc
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
+ */
+class AuthenticationEventStateResolverTest extends TestCase
+{
+    public function testCanResolveState(): void
+    {
+        $resolver = new AuthenticationEventStateResolver();
+
+        $this->assertInstanceOf(Saml2::class, $resolver->fromStateArray(StateArrays::SAML2_FULL));
+        $this->assertInstanceOf(Oidc::class, $resolver->fromStateArray(StateArrays::OIDC_FULL));
+    }
+
+    public function testThrowsIfAttributesNotSet(): void
+    {
+        $resolver = new AuthenticationEventStateResolver();
+
+        $stateArray = StateArrays::SAML2_FULL;
+        unset($stateArray[AbstractState::KEY_ATTRIBUTES]);
+
+        $this->expectException(StateException::class);
+
+        $resolver->fromStateArray($stateArray);
+    }
+
+    public function testThrowsForInvalidStateArray(): void
+    {
+        $resolver = new AuthenticationEventStateResolver();
+
+        $stateArray = StateArrays::SAML2_FULL;
+        unset($stateArray[Saml2::KEY_IDENTITY_PROVIDER_METADATA]);
+
+        $this->expectException(StateException::class);
+
+        $resolver->fromStateArray($stateArray);
+    }
+}
diff --git a/tests/src/Helpers/DateTimeHelperTest.php b/tests/src/Helpers/DateTimeTest.php
similarity index 55%
rename from tests/src/Helpers/DateTimeHelperTest.php
rename to tests/src/Helpers/DateTimeTest.php
index c9ff61a..e4bbb57 100644
--- a/tests/src/Helpers/DateTimeHelperTest.php
+++ b/tests/src/Helpers/DateTimeTest.php
@@ -5,25 +5,25 @@ declare(strict_types=1);
 namespace SimpleSAML\Test\Module\accounting\Helpers;
 
 use DateInterval;
-use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
+use SimpleSAML\Module\accounting\Helpers\DateTime;
 use PHPUnit\Framework\TestCase;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\DateTimeHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\DateTime
  */
-class DateTimeHelperTest extends TestCase
+class DateTimeTest extends TestCase
 {
     public function testCanConvertDateIntervalToSeconds(): void
     {
         $interval = new DateInterval('PT10S');
 
-        $this->assertSame(10, (new DateTimeHelper())->convertDateIntervalToSeconds($interval));
+        $this->assertSame(10, (new DateTime())->convertDateIntervalToSeconds($interval));
     }
 
     public function testMinimumIntervalIsOneSecond(): void
     {
         $interval = DateInterval::createFromDateString('-10 seconds'); // Negative interval
 
-        $this->assertSame(1, (new DateTimeHelper())->convertDateIntervalToSeconds($interval));
+        $this->assertSame(1, (new DateTime())->convertDateIntervalToSeconds($interval));
     }
 }
diff --git a/tests/src/Helpers/EnvironmentHelperTest.php b/tests/src/Helpers/EnvironmentHelperTest.php
deleted file mode 100644
index c6e95ef..0000000
--- a/tests/src/Helpers/EnvironmentHelperTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Test\Module\accounting\Helpers;
-
-use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
-use PHPUnit\Framework\TestCase;
-
-/**
- * @covers \SimpleSAML\Module\accounting\Helpers\EnvironmentHelper
- */
-class EnvironmentHelperTest extends TestCase
-{
-    public function testConfirmIsCli(): void
-    {
-        $this->assertTrue((new EnvironmentHelper())->isCli());
-    }
-}
diff --git a/tests/src/Helpers/EnvironmentTest.php b/tests/src/Helpers/EnvironmentTest.php
new file mode 100644
index 0000000..cdd443e
--- /dev/null
+++ b/tests/src/Helpers/EnvironmentTest.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\Environment;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\Environment
+ */
+class EnvironmentTest extends TestCase
+{
+    public function testConfirmIsCli(): void
+    {
+        $this->assertTrue((new Environment())->isCli());
+    }
+}
diff --git a/tests/src/Helpers/FilesystemHelperTest.php b/tests/src/Helpers/FilesystemTest.php
similarity index 66%
rename from tests/src/Helpers/FilesystemHelperTest.php
rename to tests/src/Helpers/FilesystemTest.php
index afdf031..847ccb6 100644
--- a/tests/src/Helpers/FilesystemHelperTest.php
+++ b/tests/src/Helpers/FilesystemTest.php
@@ -5,19 +5,19 @@ declare(strict_types=1);
 namespace SimpleSAML\Test\Module\accounting\Helpers;
 
 use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
-use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
+use SimpleSAML\Module\accounting\Helpers\Filesystem;
 use PHPUnit\Framework\TestCase;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\Filesystem
  */
-class FilesystemHelperTest extends TestCase
+class FilesystemTest extends TestCase
 {
     public function testCanGetRealPath(): void
     {
         $path = __DIR__ . DIRECTORY_SEPARATOR . '..';
 
-        $realPath = (new FilesystemHelper())->getRealPath($path);
+        $realPath = (new Filesystem())->getRealPath($path);
 
         $this->assertSame(dirname(__DIR__), $realPath);
     }
@@ -28,6 +28,6 @@ class FilesystemHelperTest extends TestCase
 
         $this->expectException(InvalidValueException::class);
 
-        (new FilesystemHelper())->getRealPath($path);
+        (new Filesystem())->getRealPath($path);
     }
 }
diff --git a/tests/src/Helpers/HashHelperTest.php b/tests/src/Helpers/HashTest.php
similarity index 82%
rename from tests/src/Helpers/HashHelperTest.php
rename to tests/src/Helpers/HashTest.php
index 97778d3..990a31a 100644
--- a/tests/src/Helpers/HashHelperTest.php
+++ b/tests/src/Helpers/HashTest.php
@@ -4,17 +4,17 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Test\Module\accounting\Helpers;
 
-use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
-use SimpleSAML\Module\accounting\Helpers\HashHelper;
+use SimpleSAML\Module\accounting\Helpers\Arr;
+use SimpleSAML\Module\accounting\Helpers\Hash;
 use PHPUnit\Framework\TestCase;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\HashHelper
- * @uses \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\Hash
+ * @uses \SimpleSAML\Module\accounting\Helpers\Arr
  */
-class HashHelperTest extends TestCase
+class HashTest extends TestCase
 {
-    protected HashHelper $hashHelper;
+    protected Hash $hashHelper;
 
     protected string $data;
     protected string $dataSha256;
@@ -31,7 +31,7 @@ class HashHelperTest extends TestCase
 
     protected function setUp(): void
     {
-        $this->hashHelper = new HashHelper(new ArrayHelper());
+        $this->hashHelper = new Hash(new Arr());
 
         $this->data = 'test';
         $this->dataSha256 = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08';
diff --git a/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php b/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationTest.php
similarity index 84%
rename from tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php
rename to tests/src/Helpers/InstanceBuilderUsingModuleConfigurationTest.php
index 7faea47..25f33f9 100644
--- a/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php
+++ b/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationTest.php
@@ -7,15 +7,15 @@ namespace SimpleSAML\Test\Module\accounting\Helpers;
 use PHPUnit\Framework\MockObject\Stub;
 use Psr\Log\LoggerInterface;
 use SimpleSAML\Module\accounting\Exceptions\Exception;
-use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration
  */
-class InstanceBuilderUsingModuleConfigurationHelperTest extends TestCase
+class InstanceBuilderUsingModuleConfigurationTest extends TestCase
 {
     protected BuildableUsingModuleConfigurationInterface $stub;
     /** @var class-string */
@@ -45,10 +45,9 @@ class InstanceBuilderUsingModuleConfigurationHelperTest extends TestCase
      */
     public function testCanBuildClassInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(
             BuildableUsingModuleConfigurationInterface::class,
-            (new InstanceBuilderUsingModuleConfigurationHelper())->build(
+            (new InstanceBuilderUsingModuleConfiguration())->build(
                 $this->stubClass,
                 $this->moduleConfigurationStub,
                 $this->loggerStub
@@ -60,8 +59,7 @@ class InstanceBuilderUsingModuleConfigurationHelperTest extends TestCase
     {
         $this->expectException(Exception::class);
 
-        /** @psalm-suppress InvalidArgument */
-        (new InstanceBuilderUsingModuleConfigurationHelper())->build(
+        (new InstanceBuilderUsingModuleConfiguration())->build(
             ModuleConfiguration::class, // Sample class which is not buildable.
             $this->moduleConfigurationStub,
             $this->loggerStub
diff --git a/tests/src/Helpers/ModuleRoutesHelperTest.php b/tests/src/Helpers/ModuleRoutesTest.php
similarity index 70%
rename from tests/src/Helpers/ModuleRoutesHelperTest.php
rename to tests/src/Helpers/ModuleRoutesTest.php
index 5698ed5..15fd560 100644
--- a/tests/src/Helpers/ModuleRoutesHelperTest.php
+++ b/tests/src/Helpers/ModuleRoutesTest.php
@@ -5,19 +5,21 @@ declare(strict_types=1);
 namespace SimpleSAML\Test\Module\accounting\Helpers;
 
 use PHPUnit\Framework\MockObject\Stub;
-use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Error\CriticalConfigurationError;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Utils\HTTP;
 
 /**
- * @covers \SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper
+ * @covers \SimpleSAML\Module\accounting\Helpers\ModuleRoutes
  */
-class ModuleRoutesHelperTest extends TestCase
+class ModuleRoutesTest extends TestCase
 {
     protected const BASE_URL = 'https://example.org/ssp/';
     /**
-     * @var Stub|HTTP
+     * @var Stub
      */
     protected $sspHttpUtilsStub;
     protected string $moduleUrl;
@@ -35,8 +37,7 @@ class ModuleRoutesHelperTest extends TestCase
         $path = 'sample-path';
         $moduleUrlWithPath = $this->moduleUrl . '/' . $path;
 
-        /** @psalm-suppress PossiblyInvalidArgument */
-        $moduleRoutesHelper = new ModuleRoutesHelper($this->sspHttpUtilsStub);
+        $moduleRoutesHelper = new ModuleRoutes($this->sspHttpUtilsStub);
 
         $this->assertSame($moduleUrlWithPath, $moduleRoutesHelper->getUrl($path));
     }
@@ -47,10 +48,8 @@ class ModuleRoutesHelperTest extends TestCase
         $params = ['sample' => 'param'];
         $fullUrl = 'full-url-with-sample-param';
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->sspHttpUtilsStub->method('addURLParameters')->willReturn($fullUrl);
-        /** @psalm-suppress PossiblyInvalidArgument */
-        $moduleRoutesHelper = new ModuleRoutesHelper($this->sspHttpUtilsStub);
+        $moduleRoutesHelper = new ModuleRoutes($this->sspHttpUtilsStub);
 
         $this->assertSame($fullUrl, $moduleRoutesHelper->getUrl($path, $params));
     }
diff --git a/tests/src/Helpers/NetworkHelperTest.php b/tests/src/Helpers/NetworkHelperTest.php
deleted file mode 100644
index 98cfed2..0000000
--- a/tests/src/Helpers/NetworkHelperTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Test\Module\accounting\Helpers;
-
-use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
-use PHPUnit\Framework\TestCase;
-
-/**
- * @covers \SimpleSAML\Module\accounting\Helpers\NetworkHelper
- */
-class NetworkHelperTest extends TestCase
-{
-    protected string $ipAddress;
-
-    protected function setUp(): void
-    {
-        $this->ipAddress = '123.123.123.123';
-    }
-
-    public function testCanGetIpFromParameter(): void
-    {
-        $this->assertSame($this->ipAddress, (new NetworkHelper())->resolveClientIpAddress($this->ipAddress));
-    }
-
-    public function testReturnsNullForInvalidIp(): void
-    {
-        $this->assertNull((new NetworkHelper())->resolveClientIpAddress('invalid'));
-    }
-
-    public function testReturnsNullForNonExistentIp(): void
-    {
-        $this->assertNull((new NetworkHelper())->resolveClientIpAddress());
-    }
-
-    /**
-     * @backupGlobals enabled
-     */
-    public function testCanResolveIpAddress(): void
-    {
-        global $_SERVER;
-
-        $_SERVER['REMOTE_ADDR'] = $this->ipAddress;
-
-        $this->assertSame($this->ipAddress, (new NetworkHelper())->resolveClientIpAddress());
-    }
-}
diff --git a/tests/src/Helpers/NetworkTest.php b/tests/src/Helpers/NetworkTest.php
new file mode 100644
index 0000000..ba83048
--- /dev/null
+++ b/tests/src/Helpers/NetworkTest.php
@@ -0,0 +1,60 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\Network;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\Network
+ */
+class NetworkTest extends TestCase
+{
+    protected string $ipAddress;
+
+    protected function setUp(): void
+    {
+        $this->ipAddress = '123.123.123.123';
+    }
+
+    public function testCanGetIpFromParameter(): void
+    {
+        $this->assertSame($this->ipAddress, (new Network())->resolveClientIpAddress($this->ipAddress));
+    }
+
+    public function testReturnsNullForInvalidIp(): void
+    {
+        $this->assertNull((new Network())->resolveClientIpAddress('invalid'));
+    }
+
+    public function testReturnsNullForNonExistentIp(): void
+    {
+        $this->assertNull((new Network())->resolveClientIpAddress());
+    }
+
+    /**
+     * @backupGlobals enabled
+     */
+    public function testCanResolveIpAddress(): void
+    {
+        global $_SERVER;
+
+        $_SERVER['REMOTE_ADDR'] = $this->ipAddress;
+
+        $this->assertSame($this->ipAddress, (new Network())->resolveClientIpAddress());
+    }
+
+    /**
+     * @backupGlobals enabled
+     */
+    public function testReturnsNullIfIpIsNotString(): void
+    {
+        global $_SERVER;
+
+        $_SERVER['REMOTE_ADDR'] = false;
+
+        $this->assertSame(null, (new Network())->resolveClientIpAddress());
+    }
+}
diff --git a/tests/src/Helpers/ProviderResolverTest.php b/tests/src/Helpers/ProviderResolverTest.php
new file mode 100644
index 0000000..3661701
--- /dev/null
+++ b/tests/src/Helpers/ProviderResolverTest.php
@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
+use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Providers\Identity;
+use SimpleSAML\Module\accounting\Entities\Providers\Service;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+use SimpleSAML\Module\accounting\Helpers\ProviderResolver;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\ProviderResolver
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc
+ */
+class ProviderResolverTest extends TestCase
+{
+    public function testCanResolveIdentityProvider(): void
+    {
+        $samlIdp = (new ProviderResolver())
+            ->forIdentityFromMetadataArray(StateArrays::SAML2_FULL[State\Saml2::KEY_IDENTITY_PROVIDER_METADATA]);
+
+        $this->assertInstanceOf(IdentityProviderInterface::class, $samlIdp);
+        $this->assertInstanceOf(Identity\Saml2::class, $samlIdp);
+
+        $oidcIdp = (new ProviderResolver())
+            ->forIdentityFromMetadataArray(
+                StateArrays::OIDC_FULL[State\Oidc::KEY_OIDC][State\Oidc::KEY_OPEN_ID_PROVIDER_METADATA]
+            );
+
+        $this->assertInstanceOf(IdentityProviderInterface::class, $oidcIdp);
+        $this->assertInstanceOf(Identity\Oidc::class, $oidcIdp);
+    }
+
+    public function testThrowsIfCanNotResolveIdentityProvider(): void
+    {
+        $this->expectException(MetadataException::class);
+
+        (new ProviderResolver())->forIdentityFromMetadataArray(['invalid' => 'metadata']);
+    }
+
+    public function testCanResolveServiceProvider(): void
+    {
+        $samlSp = (new ProviderResolver())
+            ->forServiceFromMetadataArray(StateArrays::SAML2_FULL[State\Saml2::KEY_SERVICE_PROVIDER_METADATA]);
+
+        $this->assertInstanceOf(ServiceProviderInterface::class, $samlSp);
+        $this->assertInstanceOf(Service\Saml2::class, $samlSp);
+
+        $oidcSp = (new ProviderResolver())
+            ->forServiceFromMetadataArray(
+                StateArrays::OIDC_FULL[State\Oidc::KEY_OIDC][State\Oidc::KEY_RELYING_PARTY_METADATA]
+            );
+
+        $this->assertInstanceOf(ServiceProviderInterface::class, $oidcSp);
+        $this->assertInstanceOf(Service\Oidc::class, $oidcSp);
+    }
+
+    public function testThrowsIfCanNotResolveServiceProvider(): void
+    {
+        $this->expectException(MetadataException::class);
+
+        (new ProviderResolver())->forServiceFromMetadataArray(['invalid' => 'metadata']);
+    }
+}
diff --git a/tests/src/Helpers/RandomHelperTest.php b/tests/src/Helpers/RandomHelperTest.php
deleted file mode 100644
index cfd0da1..0000000
--- a/tests/src/Helpers/RandomHelperTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SimpleSAML\Test\Module\accounting\Helpers;
-
-use SimpleSAML\Module\accounting\Helpers\RandomHelper;
-use PHPUnit\Framework\TestCase;
-
-/**
- * @covers \SimpleSAML\Module\accounting\Helpers\RandomHelper
- */
-class RandomHelperTest extends TestCase
-{
-    public function testCanGetRandomInt(): void
-    {
-        $this->assertIsInt((new RandomHelper())->getRandomInt());
-    }
-}
diff --git a/tests/src/Helpers/RandomTest.php b/tests/src/Helpers/RandomTest.php
new file mode 100644
index 0000000..3031c21
--- /dev/null
+++ b/tests/src/Helpers/RandomTest.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\Random;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\Random
+ */
+class RandomTest extends TestCase
+{
+    public function testCanGetRandomInt(): void
+    {
+        $this->assertIsInt((new Random())->getRandomInt());
+    }
+}
diff --git a/tests/src/ModuleConfigurationTest.php b/tests/src/ModuleConfigurationTest.php
index 2c4612c..7af5525 100644
--- a/tests/src/ModuleConfigurationTest.php
+++ b/tests/src/ModuleConfigurationTest.php
@@ -147,7 +147,7 @@ class ModuleConfigurationTest extends TestCase
         );
     }
 
-    public function testThrowsForInvalidConnectiontype(): void
+    public function testThrowsForInvalidConnectionType(): void
     {
         $this->expectException(InvalidConfigurationException::class);
 
@@ -157,11 +157,11 @@ class ModuleConfigurationTest extends TestCase
         );
     }
 
-    public function testInvalidConnectionKeyThrows(): void
+    public function testThrowsIfConnectionForClassNotSet(): void
     {
         $this->expectException(InvalidConfigurationException::class);
 
-        $this->moduleConfiguration->getClassConnectionParameters('invalid');
+        $this->moduleConfiguration->getClassConnectionKey('invalid');
     }
 
     public function testCanGetDefinedConnections(): void
diff --git a/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php b/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php
index 612351f..089baaa 100644
--- a/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php
+++ b/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php
@@ -16,7 +16,7 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Providers\Builders\AuthenticationDataProviderBuilder
- * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
  * @uses \SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder
@@ -50,7 +50,6 @@ class AuthenticationDataProviderBuilderTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(
             AuthenticationDataProviderBuilder::class,
             new AuthenticationDataProviderBuilder(
@@ -66,7 +65,6 @@ class AuthenticationDataProviderBuilderTest extends TestCase
      */
     public function testCanBuildDataProvider(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $builder = new AuthenticationDataProviderBuilder(
             $this->moduleConfigurationStub,
             $this->loggerStub,
@@ -80,7 +78,6 @@ class AuthenticationDataProviderBuilderTest extends TestCase
     {
         $this->expectException(Exception::class);
 
-        /** @psalm-suppress InvalidArgument */
         (new AuthenticationDataProviderBuilder(
             $this->moduleConfigurationStub,
             $this->loggerStub,
diff --git a/tests/src/Services/HelpersManagerTest.php b/tests/src/Services/HelpersManagerTest.php
index 19915bb..0d82af9 100644
--- a/tests/src/Services/HelpersManagerTest.php
+++ b/tests/src/Services/HelpersManagerTest.php
@@ -4,23 +4,25 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Test\Module\accounting\Services;
 
-use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
-use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
-use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
-use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
-use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
-use SimpleSAML\Module\accounting\Helpers\HashHelper;
-use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
-use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
-use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
-use SimpleSAML\Module\accounting\Helpers\RandomHelper;
+use SimpleSAML\Module\accounting\Helpers\Arr;
+use SimpleSAML\Module\accounting\Helpers\Attributes;
+use SimpleSAML\Module\accounting\Helpers\AuthenticationEventStateResolver;
+use SimpleSAML\Module\accounting\Helpers\DateTime;
+use SimpleSAML\Module\accounting\Helpers\Environment;
+use SimpleSAML\Module\accounting\Helpers\Filesystem;
+use SimpleSAML\Module\accounting\Helpers\Hash;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutes;
+use SimpleSAML\Module\accounting\Helpers\Network;
+use SimpleSAML\Module\accounting\Helpers\ProviderResolver;
+use SimpleSAML\Module\accounting\Helpers\Random;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
 use PHPUnit\Framework\TestCase;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Services\HelpersManager
- * @uses \SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper
- * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\ModuleRoutes
+ * @uses \SimpleSAML\Module\accounting\Helpers\Hash
  */
 class HelpersManagerTest extends TestCase
 {
@@ -28,18 +30,23 @@ class HelpersManagerTest extends TestCase
     {
         $helpersManager = new HelpersManager();
 
-        $this->assertInstanceOf(ArrayHelper::class, $helpersManager->getArrayHelper());
-        $this->assertInstanceOf(AttributesHelper::class, $helpersManager->getAttributesHelper());
-        $this->assertInstanceOf(DateTimeHelper::class, $helpersManager->getDateTimeHelper());
-        $this->assertInstanceOf(EnvironmentHelper::class, $helpersManager->getEnvironmentHelper());
-        $this->assertInstanceOf(FilesystemHelper::class, $helpersManager->getFilesystemHelper());
-        $this->assertInstanceOf(HashHelper::class, $helpersManager->getHashHelper());
+        $this->assertInstanceOf(Arr::class, $helpersManager->getArr());
+        $this->assertInstanceOf(Attributes::class, $helpersManager->getAttributes());
+        $this->assertInstanceOf(DateTime::class, $helpersManager->getDateTime());
+        $this->assertInstanceOf(Environment::class, $helpersManager->getEnvironment());
+        $this->assertInstanceOf(Filesystem::class, $helpersManager->getFilesystem());
+        $this->assertInstanceOf(Hash::class, $helpersManager->getHash());
         $this->assertInstanceOf(
-            InstanceBuilderUsingModuleConfigurationHelper::class,
-            $helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()
+            InstanceBuilderUsingModuleConfiguration::class,
+            $helpersManager->getInstanceBuilderUsingModuleConfiguration()
         );
-        $this->assertInstanceOf(NetworkHelper::class, $helpersManager->getNetworkHelper());
-        $this->assertInstanceOf(RandomHelper::class, $helpersManager->getRandomHelper());
-        $this->assertInstanceOf(ModuleRoutesHelper::class, $helpersManager->getModuleRoutesHelper());
+        $this->assertInstanceOf(Network::class, $helpersManager->getNetwork());
+        $this->assertInstanceOf(Random::class, $helpersManager->getRandom());
+        $this->assertInstanceOf(ModuleRoutes::class, $helpersManager->getModuleRoutes());
+        $this->assertInstanceOf(
+            AuthenticationEventStateResolver::class,
+            $helpersManager->getAuthenticationEventStateResolver()
+        );
+        $this->assertInstanceOf(ProviderResolver::class, $helpersManager->getProviderResolver());
     }
 }
diff --git a/tests/src/Services/JobRunner/RateLimiterTest.php b/tests/src/Services/JobRunner/RateLimiterTest.php
index 9666090..316ef1f 100644
--- a/tests/src/Services/JobRunner/RateLimiterTest.php
+++ b/tests/src/Services/JobRunner/RateLimiterTest.php
@@ -11,7 +11,7 @@ use SimpleSAML\Module\accounting\Services\JobRunner\RateLimiter;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Services\JobRunner\RateLimiter
- * @uses \SimpleSAML\Module\accounting\Helpers\DateTimeHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\DateTime
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
 class RateLimiterTest extends TestCase
diff --git a/tests/src/Services/JobRunnerTest.php b/tests/src/Services/JobRunnerTest.php
index 04af8e4..15b57fe 100644
--- a/tests/src/Services/JobRunnerTest.php
+++ b/tests/src/Services/JobRunnerTest.php
@@ -16,9 +16,9 @@ use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
 use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
 use SimpleSAML\Module\accounting\Exceptions\Exception;
 use SimpleSAML\Module\accounting\Exceptions\StoreException;
-use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
-use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
-use SimpleSAML\Module\accounting\Helpers\RandomHelper;
+use SimpleSAML\Module\accounting\Helpers\DateTime;
+use SimpleSAML\Module\accounting\Helpers\Environment;
+use SimpleSAML\Module\accounting\Helpers\Random;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Module\accounting\Services\HelpersManager;
 use SimpleSAML\Module\accounting\Services\JobRunner;
@@ -30,73 +30,71 @@ use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerIn
 
 /**
  * @covers \SimpleSAML\Module\accounting\Services\JobRunner
- *
- * @psalm-suppress all
  */
 class JobRunnerTest extends TestCase
 {
     /**
-     * @var Stub|ModuleConfiguration
+     * @var Stub
      */
     protected $moduleConfigurationStub;
     /**
-     * @var Stub|Configuration
+     * @var Stub
      */
     protected $sspConfigurationStub;
     /**
-     * @var MockObject|LoggerInterface
+     * @var MockObject
      */
     protected $loggerMock;
     /**
-     * @var MockObject|CacheInterface
+     * @var MockObject
      */
     protected $cacheMock;
     /**
-     * @var Stub|JobRunner\State
+     * @var Stub
      */
     protected $stateStub;
     /**
-     * @var Stub|JobRunner\RateLimiter
+     * @var Stub
      */
     protected $rateLimiterMock;
     /**
-     * @var Stub|AuthenticationDataTrackerBuilder
+     * @var Stub
      */
     protected $authenticationDataTrackerBuilderStub;
     /**
-     * @var MockObject|AuthenticationDataTrackerInterface
+     * @var MockObject
      */
     protected $authenticationDataTrackerMock;
     /**
-     * @var Stub|JobsStoreBuilder
+     * @var Stub
      */
     protected $jobsStoreBuilderStub;
     /**
-     * @var Stub|RandomHelper
+     * @var Stub
      */
     protected $randomHelperStub;
     /**
-     * @var Stub|EnvironmentHelper
+     * @var Stub
      */
     protected $environmentHelperStub;
     /**
-     * @var Stub|DateTimeHelper
+     * @var Stub
      */
     protected $dateTimeHelperStub;
     /**
-     * @var Stub|HelpersManager
+     * @var Stub
      */
     protected $helpersManagerStub;
     /**
-     * @var Stub|JobsStoreInterface
+     * @var Stub
      */
     protected $jobsStoreMock;
     /**
-     * @var Stub|JobInterface
+     * @var Stub
      */
     protected $jobStub;
     /**
-     * @var Stub|AbstractPayload
+     * @var Stub
      */
     protected $payloadStub;
 
@@ -111,9 +109,9 @@ class JobRunnerTest extends TestCase
         $this->cacheMock = $this->createMock(CacheInterface::class);
         $this->stateStub = $this->createStub(JobRunner\State::class);
         $this->rateLimiterMock = $this->createMock(JobRunner\RateLimiter::class);
-        $this->randomHelperStub = $this->createStub(RandomHelper::class);
-        $this->environmentHelperStub = $this->createStub(EnvironmentHelper::class);
-        $this->dateTimeHelperStub = $this->createStub(DateTimeHelper::class);
+        $this->randomHelperStub = $this->createStub(Random::class);
+        $this->environmentHelperStub = $this->createStub(Environment::class);
+        $this->dateTimeHelperStub = $this->createStub(DateTime::class);
         $this->helpersManagerStub = $this->createStub(HelpersManager::class);
         $this->jobsStoreMock = $this->createMock(JobsStoreInterface::class);
         $this->jobStub = $this->createStub(JobInterface::class);
@@ -126,7 +124,7 @@ class JobRunnerTest extends TestCase
     public function testCanCreateInstance(): void
     {
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->assertInstanceOf(
             JobRunner::class,
@@ -151,7 +149,7 @@ class JobRunnerTest extends TestCase
     public function testPreRunValidationFailsForSameJobRunnerId(): void
     {
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->cacheMock->method('get')->willReturn($this->stateStub);
@@ -188,7 +186,7 @@ class JobRunnerTest extends TestCase
     public function testPreRunValidationFailsForStaleState(): void
     {
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(321);
         $this->stateStub->method('isStale')->willReturn(true);
@@ -225,7 +223,7 @@ class JobRunnerTest extends TestCase
     public function testPreRunValidationPassesWhenStateIsNull(): void
     {
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->cacheMock->method('get')->willReturn(null);
 
@@ -261,7 +259,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(321);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -299,7 +297,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(321);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -339,7 +337,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(321);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -375,7 +373,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(321);
         $this->stateStub->method('isStale')->willReturn(true);
@@ -420,7 +418,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(new DateInterval('PT1S'));
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->cacheMock->method('get')->willReturn(null);
 
@@ -462,11 +460,11 @@ class JobRunnerTest extends TestCase
             ->willReturn(new DateInterval('PT20S'));
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
         $this->dateTimeHelperStub->method('convertDateIntervalToSeconds')->willReturn(20);
-        $this->helpersManagerStub->method('getDateTimeHelper')->willReturn($this->dateTimeHelperStub);
+        $this->helpersManagerStub->method('getDateTime')->willReturn($this->dateTimeHelperStub);
 
         ini_set('max_execution_time', '10');
 
@@ -508,7 +506,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->cacheMock->method('get')->willReturn(null);
 
@@ -547,7 +545,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
             null,
@@ -588,7 +586,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
             null,
@@ -629,7 +627,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(321);
 
@@ -672,7 +670,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(true);
@@ -716,7 +714,7 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -761,9 +759,9 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(true);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -816,9 +814,9 @@ class JobRunnerTest extends TestCase
             ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -870,9 +868,9 @@ class JobRunnerTest extends TestCase
             ->willReturn('mock');
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -937,9 +935,9 @@ class JobRunnerTest extends TestCase
             ->willReturn('mock');
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -1001,9 +999,9 @@ class JobRunnerTest extends TestCase
             ->willReturn(0);
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -1072,9 +1070,9 @@ class JobRunnerTest extends TestCase
             ->willReturn('mock');
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
@@ -1138,9 +1136,9 @@ class JobRunnerTest extends TestCase
             ->willReturn('mock');
 
         $this->randomHelperStub->method('getRandomInt')->willReturn(123);
-        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->helpersManagerStub->method('getRandom')->willReturn($this->randomHelperStub);
         $this->environmentHelperStub->method('isCli')->willReturn(false);
-        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->helpersManagerStub->method('getEnvironment')->willReturn($this->environmentHelperStub);
 
         $this->stateStub->method('getJobRunnerId')->willReturn(123);
         $this->stateStub->method('isStale')->willReturn(false);
diff --git a/tests/src/Stores/Bases/AbstractStoreTest.php b/tests/src/Stores/Bases/AbstractStoreTest.php
index bf839e0..9e45460 100644
--- a/tests/src/Stores/Bases/AbstractStoreTest.php
+++ b/tests/src/Stores/Bases/AbstractStoreTest.php
@@ -17,11 +17,11 @@ class AbstractStoreTest extends TestCase
 {
     protected AbstractStore $abstractStore;
     /**
-     * @var Stub|ModuleConfiguration
+     * @var Stub
      */
     protected $moduleConfigurationStub;
     /**
-     * @var Stub|LoggerInterface
+     * @var Stub
      */
     protected $loggerStub;
 
@@ -54,7 +54,6 @@ class AbstractStoreTest extends TestCase
     public function testCanBuildInstance(): void
     {
         $this->assertInstanceOf(AbstractStore::class, $this->abstractStore);
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             AbstractStore::class,
             $this->abstractStore::build($this->moduleConfigurationStub, $this->loggerStub)
diff --git a/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php b/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php
index 7687987..4c1fff1 100644
--- a/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php
+++ b/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php
@@ -35,7 +35,6 @@ class AbstractRawEntityTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $rawEntityInstance = new class ($this->rawRow, $this->abstractPlatformStub) extends AbstractRawEntity {
             protected function validate(
                 array $rawRow
@@ -47,7 +46,6 @@ class AbstractRawEntityTest extends TestCase
 
     public function testCanResolveDateTimeImmutable(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $rawEntityInstance = new class ($this->rawRow, $this->abstractPlatformStub) extends AbstractRawEntity {
             protected function validate(
                 array $rawRow
@@ -63,7 +61,6 @@ class AbstractRawEntityTest extends TestCase
     {
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new class ($this->rawRow, $this->abstractPlatformStub) extends AbstractRawEntity {
             protected function validate(
                 array $rawRow
diff --git a/tests/src/Stores/Builders/DataStoreBuilderTest.php b/tests/src/Stores/Builders/DataStoreBuilderTest.php
index 8a51c7b..307a5a4 100644
--- a/tests/src/Stores/Builders/DataStoreBuilderTest.php
+++ b/tests/src/Stores/Builders/DataStoreBuilderTest.php
@@ -17,7 +17,7 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
 /**
  * @covers \SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
- * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
  * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
@@ -45,7 +45,6 @@ class DataStoreBuilderTest extends TestCase
 
         $this->helpersManager = new HelpersManager();
 
-        /** @psalm-suppress InvalidArgument */
         $this->dataStoreBuilder = new DataStoreBuilder(
             $this->moduleConfigurationStub,
             $this->loggerStub,
diff --git a/tests/src/Stores/Builders/JobsStoreBuilderTest.php b/tests/src/Stores/Builders/JobsStoreBuilderTest.php
index 47bb15e..cb1add5 100644
--- a/tests/src/Stores/Builders/JobsStoreBuilderTest.php
+++ b/tests/src/Stores/Builders/JobsStoreBuilderTest.php
@@ -25,7 +25,7 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
- * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
@@ -48,7 +48,6 @@ class JobsStoreBuilderTest extends TestCase
 
         $this->helpersManager = new HelpersManager();
 
-        /** @psalm-suppress InvalidArgument */
         $this->jobsStoreBuilder = new JobsStoreBuilder(
             $this->moduleConfigurationStub,
             $this->loggerStub,
@@ -73,7 +72,6 @@ class JobsStoreBuilderTest extends TestCase
         $invalidStore = new class {
         };
 
-        /** @psalm-suppress InvalidArgument */
         $storeBuilder = new class (
             $moduleConfigurationStub,
             $this->loggerStub,
@@ -90,7 +88,6 @@ class JobsStoreBuilderTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         $storeBuilder->build(get_class($invalidStore));
     }
 
@@ -102,7 +99,6 @@ class JobsStoreBuilderTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         (new JobsStoreBuilder($moduleConfigurationStub, $this->loggerStub, $this->helpersManager))
             ->build('invalid');
     }
@@ -135,7 +131,6 @@ class JobsStoreBuilderTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         (new JobsStoreBuilder($moduleConfigurationStub, $this->loggerStub, $this->helpersManager))
             ->build(get_class($sampleStore));
     }
diff --git a/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php b/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php
index 3a33be7..8a932f4 100644
--- a/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php
+++ b/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php
@@ -21,7 +21,7 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
- * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Filesystem
  * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
@@ -61,7 +61,6 @@ class AbstractMigratorTest extends TestCase
      */
     public function testCanGatherMigrationClassesFromDirectory(): void
     {
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $directory = $this->getSampleMigrationsDirectory();
@@ -80,7 +79,6 @@ class AbstractMigratorTest extends TestCase
      */
     public function testCanRunMigrationClasses(): void
     {
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
@@ -105,7 +103,6 @@ class AbstractMigratorTest extends TestCase
      */
     public function testCanGatherOnlyMigrationClasses(): void
     {
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $directory = __DIR__;
@@ -131,7 +128,6 @@ class AbstractMigratorTest extends TestCase
             }
         };
 
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $this->expectException(MigrationException::class);
@@ -144,7 +140,6 @@ class AbstractMigratorTest extends TestCase
      */
     public function testCanGetNonImplementedMigrationClasses(): void
     {
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
@@ -165,7 +160,6 @@ class AbstractMigratorTest extends TestCase
      */
     public function testCanFindOutIfNonImplementedMigrationClassesExist(): void
     {
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
@@ -182,7 +176,6 @@ class AbstractMigratorTest extends TestCase
      */
     public function testCanRunNonImplementedMigrationClasses(): void
     {
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
diff --git a/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php b/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php
index bd91d5c..d1cd3d0 100644
--- a/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php
+++ b/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php
@@ -37,7 +37,6 @@ class FactoryTest extends TestCase
 
     public function testCanBuildConnection(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $factory = new Factory($this->moduleConfiguration, $this->loggerServiceMock);
 
         $this->assertInstanceOf(Connection::class, $factory->buildConnection('doctrine_dbal_pdo_sqlite'));
@@ -48,7 +47,6 @@ class FactoryTest extends TestCase
      */
     public function testCanBuildMigrator(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $factory = new Factory($this->moduleConfiguration, $this->loggerServiceMock);
 
         $connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
diff --git a/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php b/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php
index 223dfc3..a7d4496 100644
--- a/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php
+++ b/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php
@@ -31,7 +31,7 @@ use function PHPUnit\Framework\assertFalse;
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
  * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
- * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Filesystem
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
@@ -69,7 +69,6 @@ class MigratorTest extends TestCase
     {
         $this->assertFalse($this->schemaManager->tablesExist([$this->tableName]));
 
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $this->assertTrue($migrator->needsSetup());
@@ -90,7 +89,6 @@ class MigratorTest extends TestCase
             ->method('warning')
             ->with($this->stringContains('setup is not needed'));
 
-        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $this->assertTrue($migrator->needsSetup());
@@ -106,7 +104,6 @@ class MigratorTest extends TestCase
      */
     public function testCanRunMigrationClasses(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
@@ -134,7 +131,6 @@ class MigratorTest extends TestCase
             }
         };
 
-        /** @psalm-suppress InvalidArgument */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
@@ -150,7 +146,6 @@ class MigratorTest extends TestCase
      */
     public function testCanGetImplementedMigrationClasses(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $migrator = new Migrator($this->connection, $this->loggerServiceMock);
 
         $migrator->runSetup();
@@ -174,7 +169,6 @@ class MigratorTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         (new Migrator($connectionStub, $this->loggerServiceMock));
     }
 
@@ -191,7 +185,6 @@ class MigratorTest extends TestCase
         $connectionStub = $this->createStub(Connection::class);
         $connectionStub->method('dbal')->willReturn($dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migrator = new Migrator($connectionStub, $this->loggerServiceMock);
 
         $this->expectException(StoreException::class);
@@ -212,7 +205,6 @@ class MigratorTest extends TestCase
         $connectionStub = $this->createStub(Connection::class);
         $connectionStub->method('dbal')->willReturn($dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migrator = new Migrator($connectionStub, $this->loggerServiceMock);
 
         $this->expectException(StoreException::class);
@@ -235,7 +227,6 @@ class MigratorTest extends TestCase
         $connectionStub->method('dbal')->willReturn($dbalStub);
         $connectionStub->method('preparePrefixedTableName')->willReturn(Migrator::TABLE_NAME);
 
-        /** @psalm-suppress InvalidArgument */
         $migrator = new Migrator($connectionStub, $this->loggerServiceMock);
         $migrator->runSetup();
 
@@ -255,7 +246,6 @@ class MigratorTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         (new Migrator($connectionStub, $this->loggerServiceMock))->getImplementedMigrationClasses();
     }
 
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php
index 95861de..c08603b 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php
@@ -5,20 +5,20 @@ declare(strict_types=1);
 namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
 
 use PHPUnit\Framework\MockObject\Stub;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState;
 use PHPUnit\Framework\TestCase;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState
- * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
- * @uses \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Hash
+ * @uses \SimpleSAML\Module\accounting\Helpers\Arr
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
 class HashDecoratedStateTest extends TestCase
 {
     /**
-     * @var Stub|State
+     * @var Stub
      */
     protected $stateStub;
     protected string $identityProviderEntityId;
@@ -38,7 +38,7 @@ class HashDecoratedStateTest extends TestCase
 
     protected function setUp(): void
     {
-        $this->stateStub = $this->createStub(State::class);
+        $this->stateStub = $this->createStub(State\Saml2::class);
         $this->identityProviderEntityId = 'idpEntityId';
         $this->stateStub->method('getIdentityProviderEntityId')->willReturn($this->identityProviderEntityId);
         $this->identityProviderMetadata = ['idp' => 'metadata'];
@@ -53,13 +53,11 @@ class HashDecoratedStateTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(HashDecoratedState::class, new HashDecoratedState($this->stateStub));
     }
 
     public function testCanGetHashedProperties(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $hashDecoratedState = new HashDecoratedState($this->stateStub);
 
         $this->assertSame($this->stateStub, $hashDecoratedState->getState());
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php
index 53c288b..4c93391 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000000CreateIdpTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000000CreateIdpTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000000CreateIdpTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000000CreateIdpTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000000CreateIdpTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000000CreateIdpTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php
index 6505b8c..60e725d 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000100CreateIdpVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000100CreateIdpVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000100CreateIdpVersionTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php
index fd6506f..66eb8ec 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000200CreateSpTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000200CreateSpTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000200CreateSpTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000200CreateSpTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000200CreateSpTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000200CreateSpTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php
index f51a394..ebbf6d2 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000300CreateSpVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000300CreateSpVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000300CreateSpVersionTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php
index 1631c08..f20463f 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000400CreateUserTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000400CreateUserTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000400CreateUserTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000400CreateUserTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000400CreateUserTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000400CreateUserTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php
index 4c99e35..8a6cf64 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000500CreateUserVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000500CreateUserVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000500CreateUserVersionTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php
index 61b3f26..1c18391 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php
@@ -69,7 +69,6 @@ class Version20220801000600CreateIdpSpUserVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration =
             new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
@@ -86,7 +85,6 @@ class Version20220801000600CreateIdpSpUserVersionTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration =
             new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
@@ -101,7 +99,6 @@ class Version20220801000600CreateIdpSpUserVersionTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration =
             new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connectionStub);
         $this->expectException(MigrationException::class);
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php
index 12d0b92..d309767 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php
@@ -68,7 +68,6 @@ class Version20220801000700CreateAuthenticationEventTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
@@ -84,7 +83,6 @@ class Version20220801000700CreateAuthenticationEventTableTest extends TestCase
         $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
         $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->revert();
@@ -98,7 +96,6 @@ class Version20220801000700CreateAuthenticationEventTableTest extends TestCase
         $this->connectionStub->method('preparePrefixedTableName')
             ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
 
-        /** @psalm-suppress InvalidArgument */
         $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connectionStub);
         $this->expectException(MigrationException::class);
         $migration->run();
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php
index a672fcb..3158985 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php
@@ -7,6 +7,7 @@ namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineD
 use DateTimeImmutable;
 use Doctrine\DBAL\Platforms\AbstractPlatform;
 use PHPUnit\Framework\MockObject\Stub;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
 use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawActivity;
 use PHPUnit\Framework\TestCase;
@@ -32,9 +33,10 @@ class RawActivityTest extends TestCase
 
     protected array $rawRow;
     /**
-     * @var AbstractPlatform|Stub
+     * @var Stub
      */
     protected $abstractPlatformStub;
+    protected string $authenticationProtocolDesignation;
 
     protected function setUp(): void
     {
@@ -42,12 +44,15 @@ class RawActivityTest extends TestCase
         $this->userAttributes = ['user' => 'attribute'];
         $this->happenedAt = '2022-02-22 22:22:22';
         $this->clientIpAddress = '123.123.123.123';
+        $this->authenticationProtocolDesignation = Saml2::DESIGNATION;
 
         $this->rawRow = [
             TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA => serialize($this->serviceProviderMetadata),
             TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES => serialize($this->userAttributes),
             TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT => $this->happenedAt,
             TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS => $this->clientIpAddress,
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION =>
+                $this->authenticationProtocolDesignation,
         ];
         $this->abstractPlatformStub = $this->createStub(AbstractPlatform::class);
         $this->abstractPlatformStub->method('getDateTimeFormatString')->willReturn(DateTime::DEFAULT_FORMAT);
@@ -55,7 +60,6 @@ class RawActivityTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $rawActivity = new RawActivity($this->rawRow, $this->abstractPlatformStub);
 
         $this->assertInstanceOf(RawActivity::class, $rawActivity);
@@ -63,25 +67,36 @@ class RawActivityTest extends TestCase
 
     public function testCanGetProperties(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $rawActivity = new RawActivity($this->rawRow, $this->abstractPlatformStub);
 
         $this->assertInstanceOf(DateTimeImmutable::class, $rawActivity->getHappenedAt());
         $this->assertSame($this->serviceProviderMetadata, $rawActivity->getServiceProviderMetadata());
         $this->assertSame($this->userAttributes, $rawActivity->getUserAttributes());
         $this->assertSame($this->clientIpAddress, $rawActivity->getClientIpAddress());
+        $this->assertSame(
+            $this->authenticationProtocolDesignation,
+            $rawActivity->getAuthenticationProtocolDesignation()
+        );
     }
 
-    public function testIpAddressCanBeMissing(): void
+    public function testIpAddressCanBeNull(): void
     {
         $rawRow = $this->rawRow;
         unset($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS]);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $rawActivity = new RawActivity($rawRow, $this->abstractPlatformStub);
         $this->assertNull($rawActivity->getClientIpAddress());
     }
 
+    public function testAuthenticationProtocolDesignationCanBeNull(): void
+    {
+        $rawRow = $this->rawRow;
+        unset($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_AUTHENTICATION_PROTOCOL_DESIGNATION]);
+
+        $rawActivity = new RawActivity($rawRow, $this->abstractPlatformStub);
+        $this->assertNull($rawActivity->getAuthenticationProtocolDesignation());
+    }
+
     public function testThrowsIfColumnNotPresent(): void
     {
         $rawRow = $this->rawRow;
@@ -89,7 +104,6 @@ class RawActivityTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawActivity($rawRow, $this->abstractPlatformStub);
     }
 
@@ -100,7 +114,6 @@ class RawActivityTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawActivity($rawRow, $this->abstractPlatformStub);
     }
 
@@ -111,7 +124,6 @@ class RawActivityTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawActivity($rawRow, $this->abstractPlatformStub);
     }
 
@@ -122,7 +134,6 @@ class RawActivityTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawActivity($rawRow, $this->abstractPlatformStub);
     }
 
@@ -133,7 +144,6 @@ class RawActivityTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawActivity($rawRow, $this->abstractPlatformStub);
     }
 
@@ -144,7 +154,6 @@ class RawActivityTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawActivity($rawRow, $this->abstractPlatformStub);
     }
 }
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php
index 3da4ab6..63c4518 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php
@@ -64,7 +64,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             RawConnectedServiceProvider::class,
             new RawConnectedServiceProvider($this->rawRow, $this->abstractPlatformStub)
@@ -73,7 +72,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
     public function testCanGetProperties(): void
     {
-        /** @psalm-suppress PossiblyInvalidArgument */
         $rawConnectedServiceProvider = new RawConnectedServiceProvider($this->rawRow, $this->abstractPlatformStub);
 
         $this->assertSame($this->numberOfAuthentications, $rawConnectedServiceProvider->getNumberOfAuthentications());
@@ -98,7 +96,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -109,7 +106,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -120,7 +116,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -131,7 +126,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -142,7 +136,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -153,7 +146,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -164,7 +156,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 
@@ -175,7 +166,6 @@ class RawConnectedServiceProviderTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
     }
 }
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php
index 80b1137..bf93c30 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php
@@ -9,6 +9,7 @@ use DateTimeImmutable;
 use Exception;
 use PHPUnit\Framework\MockObject\Stub;
 use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2;
 use SimpleSAML\Module\accounting\Exceptions\StoreException;
 use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
 use SimpleSAML\Module\accounting\ModuleConfiguration;
@@ -23,7 +24,7 @@ use SimpleSAML\Test\Module\accounting\Constants\DateTime;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
- * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Filesystem
  * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
@@ -38,15 +39,13 @@ use SimpleSAML\Test\Module\accounting\Constants\DateTime;
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000600CreateIdpSpUserVersionTable
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000700CreateAuthenticationEventTable
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
- *
- * @psalm-suppress all
  */
 class RepositoryTest extends TestCase
 {
     protected Connection $connection;
     protected \Doctrine\DBAL\Connection $dbal;
     /**
-     * @var Stub|LoggerInterface
+     * @var Stub
      */
     protected $loggerStub;
     protected Migrator $migrator;
@@ -64,12 +63,13 @@ class RepositoryTest extends TestCase
     protected Repository $repository;
     protected DateTimeImmutable $createdAt;
     /**
-     * @var Stub|Connection
+     * @var Stub
      */
     protected $connectionStub;
     protected string $spEntityIdHash;
     protected string $spMetadata;
     protected string $clientIpAddress;
+    protected string $authenticationProtocolDesignation;
 
     /**
      * @throws StoreException
@@ -119,6 +119,7 @@ class RepositoryTest extends TestCase
 
         $this->createdAt = new DateTimeImmutable();
         $this->clientIpAddress = '123.123.123.123';
+        $this->authenticationProtocolDesignation = Saml2::DESIGNATION;
     }
 
     public function testCanCreateInstance(): void
@@ -467,7 +468,7 @@ class RepositoryTest extends TestCase
 
         $this->assertSame(0, (int)$authenticationEventCounterQueryBuilder->executeQuery()->fetchOne());
 
-        $this->repository->insertAuthenticationEvent($idpSpUserVersionId, $happenedAt, null, $createdAt);
+        $this->repository->insertAuthenticationEvent($idpSpUserVersionId, $happenedAt, null, null, $createdAt);
 
         $this->assertSame(1, (int)$authenticationEventCounterQueryBuilder->executeQuery()->fetchOne());
     }
@@ -521,6 +522,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
 
@@ -550,6 +552,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
         $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
@@ -592,6 +595,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
 
@@ -631,6 +635,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
         $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
@@ -710,6 +715,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
 
@@ -720,6 +726,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
         $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
@@ -729,6 +736,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
         $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
@@ -757,6 +765,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
         $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
@@ -814,6 +823,7 @@ class RepositoryTest extends TestCase
             $idpSpUserVersionId,
             $this->createdAt,
             $this->clientIpAddress,
+            $this->authenticationProtocolDesignation,
             $this->createdAt
         );
 
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php
index 3af28aa..df3cdf4 100644
--- a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php
@@ -11,7 +11,7 @@ use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\MockObject\Stub;
 use Psr\Log\LoggerInterface;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Module\accounting\Exceptions\StoreException;
 use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
@@ -28,13 +28,14 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
- * @uses   \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
- * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
- * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
- * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
- * @uses   \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
- * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\Event
- * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000000CreateIdpTable
@@ -45,11 +46,11 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000500CreateUserVersionTable
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000600CreateIdpSpUserVersionTable
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000700CreateAuthenticationEventTable
- * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Filesystem
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState
- * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
- * @uses \SimpleSAML\Module\accounting\Helpers\ArrayHelper
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Hash
+ * @uses \SimpleSAML\Module\accounting\Helpers\Arr
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
  * @uses \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider
@@ -61,8 +62,9 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawActivity
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
- *
- * @psalm-suppress all
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2
+ * @uses \SimpleSAML\Module\accounting\Helpers\ProviderResolver
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2
  */
 class StoreTest extends TestCase
 {
@@ -70,19 +72,19 @@ class StoreTest extends TestCase
     protected Migrator $migrator;
     protected Stub $factoryStub;
     protected Connection $connection;
-    protected State $state;
+    protected State\Saml2 $state;
     protected Event $authenticationEvent;
     protected Store\HashDecoratedState $hashDecoratedState;
     /**
-     * @var MockObject|Store\Repository
+     * @var MockObject
      */
     protected $repositoryMock;
     /**
-     * @var Result|Stub
+     * @var Stub
      */
     protected $resultStub;
     /**
-     * @var MockObject|LoggerInterface
+     * @var MockObject
      */
     protected $loggerMock;
 
@@ -102,14 +104,13 @@ class StoreTest extends TestCase
 
         $this->loggerMock = $this->createMock(LoggerInterface::class);
 
-        /** @psalm-suppress InvalidArgument */
         $this->migrator = new Migrator($this->connection, $this->loggerMock);
 
         $this->factoryStub = $this->createStub(Factory::class);
         $this->factoryStub->method('buildConnection')->willReturn($this->connection);
         $this->factoryStub->method('buildMigrator')->willReturn($this->migrator);
 
-        $this->state = new State(StateArrays::FULL);
+        $this->state = new State\Saml2(StateArrays::SAML2_FULL);
         $this->authenticationEvent = new Event($this->state);
 
         $this->hashDecoratedState = new Store\HashDecoratedState($this->state);
@@ -123,7 +124,6 @@ class StoreTest extends TestCase
      */
     public function testCanConstructInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(
             Store::class,
             new Store(
@@ -141,7 +141,6 @@ class StoreTest extends TestCase
      */
     public function testCanBuildInstance(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(
             Store::class,
             Store::build($this->moduleConfigurationStub, $this->loggerMock)
@@ -155,7 +154,6 @@ class StoreTest extends TestCase
      */
     public function testCanPersistAuthenticationEvent(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -263,7 +261,6 @@ class StoreTest extends TestCase
     public function testResolveIdpIdThrowsOnFirstGetIdpFailure(): void
     {
         $this->repositoryMock->method('getIdp')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -287,7 +284,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getIdp')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertIdp')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -309,7 +305,6 @@ class StoreTest extends TestCase
     public function testResolveIdpVersionIdThrowsOnFirstGetIdpVersionFailure(): void
     {
         $this->repositoryMock->method('getIdpVersion')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -333,7 +328,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getIdpVersion')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertIdpVersion')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -355,7 +349,6 @@ class StoreTest extends TestCase
     public function testResolveSpIdThrowsOnFirstGetSpFailure(): void
     {
         $this->repositoryMock->method('getSp')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -379,7 +372,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getSp')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertSp')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -401,7 +393,6 @@ class StoreTest extends TestCase
     public function testResolveSpVersionIdThrowsOnFirstGetSpVersionFailure(): void
     {
         $this->repositoryMock->method('getSpVersion')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -425,7 +416,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getSpVersion')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertSpVersion')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -449,7 +439,6 @@ class StoreTest extends TestCase
         $moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
         $moduleConfigurationStub->method('getUserIdAttributeName')->willReturn('invalid');
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $moduleConfigurationStub,
             $this->loggerMock,
@@ -470,7 +459,6 @@ class StoreTest extends TestCase
     public function testResolveUserIdThrowsOnFirstGetUserFailure(): void
     {
         $this->repositoryMock->method('getUser')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -494,7 +482,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getUser')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertUser')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -516,7 +503,6 @@ class StoreTest extends TestCase
     public function testResolveUserVersionIdThrowsOnFirstGetUserVersionFailure(): void
     {
         $this->repositoryMock->method('getUserVersion')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -540,7 +526,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getUserVersion')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertUserVersion')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -562,7 +547,6 @@ class StoreTest extends TestCase
     public function testResolveIdpSpUserVersionIdThrowsOnFirstGetIdpSpUserVersionFailure(): void
     {
         $this->repositoryMock->method('getIdpSpUserVersion')->willThrowException(new Exception('test'));
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -586,7 +570,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getIdpSpUserVersion')->willReturn($this->resultStub);
         $this->repositoryMock->method('insertIdpSpUserVersion')->willThrowException(new Exception('test'));
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -609,7 +592,6 @@ class StoreTest extends TestCase
     {
         $this->repositoryMock->method('getConnectedServiceProviders')->willReturn([]);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -632,7 +614,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getConnectedServiceProviders')
             ->willReturn([RawRowResult::CONNECTED_ORGANIZATION]);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -658,7 +639,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getConnectedServiceProviders')
             ->willReturn([$rawResult]);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -679,7 +659,6 @@ class StoreTest extends TestCase
     {
         $this->repositoryMock->method('getActivity')->willReturn([]);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -702,7 +681,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getActivity')
             ->willReturn([RawRowResult::ACTIVITY]);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -728,7 +706,6 @@ class StoreTest extends TestCase
         $this->repositoryMock->method('getActivity')
             ->willReturn([$rawResult]);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -753,7 +730,6 @@ class StoreTest extends TestCase
             ->method('deleteAuthenticationEventsOlderThan')
             ->with($dateTime);
 
-        /** @psalm-suppress InvalidArgument */
         $store = new Store(
             $this->moduleConfigurationStub,
             $this->loggerMock,
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php b/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php
index 61370f2..e272b82 100644
--- a/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php
+++ b/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php
@@ -10,7 +10,7 @@ use Doctrine\DBAL\Platforms\SqlitePlatform;
 use PHPUnit\Framework\MockObject\Stub;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
 use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
 use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\RawJob;
@@ -19,9 +19,10 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
 /**
  * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\RawJob
  * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
- * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  */
 class RawJobTest extends TestCase
@@ -37,7 +38,7 @@ class RawJobTest extends TestCase
         $this->abstractPlatformStub->method('getDateTimeFormatString')
             ->willReturn('YYYY-MM-DD HH:MM:SS');
 
-        $this->authenticationEvent = new Event(new State(StateArrays::FULL));
+        $this->authenticationEvent = new Event(new State\Saml2(StateArrays::SAML2_FULL));
         $this->validRawRow = [
             Store\TableConstants::COLUMN_NAME_ID => 1,
             Store\TableConstants::COLUMN_NAME_PAYLOAD => serialize($this->authenticationEvent),
@@ -63,7 +64,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 
@@ -74,7 +74,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 
@@ -85,7 +84,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 
@@ -96,7 +94,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new Store\RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 
@@ -107,7 +104,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new Store\RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 
@@ -118,7 +114,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 
@@ -129,7 +124,6 @@ class RawJobTest extends TestCase
 
         $this->expectException(UnexpectedValueException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new Store\RawJob($invalidRawRow, $this->abstractPlatformStub);
     }
 }
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php b/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php
index d12416a..3924415 100644
--- a/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php
+++ b/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php
@@ -9,7 +9,7 @@ use Exception;
 use PHPUnit\Framework\MockObject\Stub;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob;
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
 use SimpleSAML\Module\accounting\Entities\GenericJob;
@@ -29,7 +29,7 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
- * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Filesystem
  * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
@@ -42,9 +42,10 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
- * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
  */
@@ -71,7 +72,6 @@ class RepositoryTest extends TestCase
 
         $this->loggerServiceStub = $this->createStub(Logger::class);
 
-        /** @psalm-suppress InvalidArgument */
         $this->migrator = new Migrator($this->connection, $this->loggerServiceStub);
 
         $this->factoryStub = $this->createStub(Factory::class);
@@ -84,7 +84,6 @@ class RepositoryTest extends TestCase
         $this->jobStub->method('getType')->willReturn(GenericJob::class);
         $this->jobStub->method('getCreatedAt')->willReturn(new DateTimeImmutable());
 
-        /** @psalm-suppress InvalidArgument */
         $this->jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerServiceStub,
@@ -102,14 +101,12 @@ class RepositoryTest extends TestCase
      */
     public function testCanInsertAndGetJob(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         $this->jobsStore->runSetup();
 
         $this->assertNull($repository->getNext());
 
-        /** @psalm-suppress InvalidArgument */
         $repository->insert($this->jobStub);
 
         $this->assertNotNull($repository->getNext());
@@ -120,14 +117,12 @@ class RepositoryTest extends TestCase
      */
     public function testInsertThrowsIfJobsStoreSetupNotRan(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         //$this->jobsStore->runSetup();
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         $repository->insert($this->jobStub);
     }
 
@@ -137,7 +132,6 @@ class RepositoryTest extends TestCase
      */
     public function testInsertThrowsForInvalidJobType(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         $this->jobsStore->runSetup();
@@ -150,7 +144,6 @@ class RepositoryTest extends TestCase
         $jobStub->method('getType')->willReturn($invalidType);
         $jobStub->method('getCreatedAt')->willReturn(new DateTimeImmutable());
 
-        /** @psalm-suppress InvalidArgument */
         $repository->insert($jobStub);
     }
 
@@ -159,7 +152,6 @@ class RepositoryTest extends TestCase
      */
     public function testGetNextThrowsIfJobsStoreSetupNotRan(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         //$this->jobsStore->runSetup();
@@ -175,7 +167,6 @@ class RepositoryTest extends TestCase
      */
     public function testGetNextThrowsForInvalidJobType(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         $this->jobsStore->runSetup();
@@ -186,7 +177,6 @@ class RepositoryTest extends TestCase
         $jobStub->method('getType')->willReturn(AbstractJob::class);
         $jobStub->method('getCreatedAt')->willReturn(new DateTimeImmutable());
 
-        /** @psalm-suppress InvalidArgument */
         $repository->insert($jobStub);
 
         $this->expectException(StoreException::class);
@@ -201,13 +191,11 @@ class RepositoryTest extends TestCase
      */
     public function testCanDeleteJob(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         $this->jobsStore->runSetup();
 
         $this->assertFalse($repository->delete(1));
-        /** @psalm-suppress InvalidArgument */
         $repository->insert($this->jobStub);
         $job = $repository->getNext();
         if ($job === null) {
@@ -226,7 +214,6 @@ class RepositoryTest extends TestCase
      */
     public function testDeleteThrowsWhenJobsStoreSetupNotRan(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         //$this->jobsStore->runSetup();
@@ -242,17 +229,15 @@ class RepositoryTest extends TestCase
      */
     public function testCanGetSpecificJobType(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
         // Running setup will ensure that all migrations are ran.
         $this->jobsStore->runSetup();
 
         $this->assertNull($repository->getNext());
 
-        /** @psalm-suppress InvalidArgument */
         $repository->insert($this->jobStub);
 
-        $authenticationEvent = new Event(new State(StateArrays::FULL));
+        $authenticationEvent = new Event(new State\Saml2(StateArrays::SAML2_FULL));
         $authenticationEventJob = new Event\Job($authenticationEvent);
 
         $repository->insert($authenticationEventJob);
@@ -264,7 +249,6 @@ class RepositoryTest extends TestCase
     {
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress InvalidArgument */
         new Repository($this->connection, 'invalid-table-name', $this->loggerServiceStub);
     }
 }
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php b/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php
index dfaea6d..d93c787 100644
--- a/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php
+++ b/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php
@@ -9,7 +9,7 @@ use Doctrine\DBAL\Exception;
 use PHPUnit\Framework\MockObject\Stub;
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Module\accounting\Entities\Authentication\Event;
-use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\State;
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob;
 use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
 use SimpleSAML\Module\accounting\Entities\GenericJob;
@@ -32,7 +32,7 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
- * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Filesystem
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
@@ -42,9 +42,10 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository
  * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
- * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractState
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\State\Saml2
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
- * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Network
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
  */
@@ -69,7 +70,6 @@ class StoreTest extends TestCase
 
         $this->loggerStub = $this->createStub(Logger::class);
 
-        /** @psalm-suppress InvalidArgument */
         $this->migrator = new Migrator($this->connection, $this->loggerStub);
 
         $this->factoryStub = $this->createStub(Factory::class);
@@ -90,7 +90,6 @@ class StoreTest extends TestCase
      */
     public function testSetupDependsOnMigratorSetup(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -114,7 +113,6 @@ class StoreTest extends TestCase
      */
     public function testSetupDependsOnMigrations(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -137,7 +135,6 @@ class StoreTest extends TestCase
      */
     public function testCanGetPrefixedTableNames(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -163,7 +160,6 @@ class StoreTest extends TestCase
         $moduleConfiguration = $this->createStub(ModuleConfiguration::class);
         $moduleConfiguration->method('getConnectionParameters')
             ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
-        /** @psalm-suppress InvalidArgument */
         $this->assertInstanceOf(Store::class, Store::build($moduleConfiguration, $this->loggerStub));
     }
 
@@ -174,7 +170,6 @@ class StoreTest extends TestCase
      */
     public function testCanEnqueueJob(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -189,14 +184,11 @@ class StoreTest extends TestCase
 
         $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->enqueue($this->jobStub);
 
         $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->enqueue($this->jobStub);
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->enqueue($this->jobStub);
 
         $this->assertSame(3, (int) $queryBuilder->executeQuery()->fetchOne());
@@ -207,7 +199,6 @@ class StoreTest extends TestCase
      */
     public function testEnqueueThrowsStoreExceptionOnNonSetupRun(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -234,7 +225,6 @@ class StoreTest extends TestCase
      */
     public function testCanDequeueJob(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -249,14 +239,11 @@ class StoreTest extends TestCase
 
         $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->enqueue($this->jobStub);
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->enqueue($this->jobStub);
 
         $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
         $jobsStore->dequeue($this->jobStub->getType());
 
         $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
@@ -269,7 +256,6 @@ class StoreTest extends TestCase
      */
     public function testCanDequeueSpecificJobType(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -279,7 +265,7 @@ class StoreTest extends TestCase
         );
         $jobsStore->runSetup();
 
-        $authenticationEvent = new Event(new State(StateArrays::FULL));
+        $authenticationEvent = new Event(new State\Saml2(StateArrays::SAML2_FULL));
         $authenticationEventJob = new Event\Job($authenticationEvent);
 
         $queryBuilder = $this->connection->dbal()->createQueryBuilder();
@@ -287,7 +273,6 @@ class StoreTest extends TestCase
 
         $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->enqueue($this->jobStub);
         $jobsStore->enqueue($authenticationEventJob);
 
@@ -308,7 +293,6 @@ class StoreTest extends TestCase
      */
     public function testDequeueThrowsWhenSetupNotRun(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -343,7 +327,6 @@ class StoreTest extends TestCase
 
         $repositoryStub->method('getNext')->willReturn($jobStub);
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -356,7 +339,6 @@ class StoreTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
         $jobsStore->dequeue($this->jobStub->getType());
     }
 
@@ -371,7 +353,6 @@ class StoreTest extends TestCase
         $repositoryStub->method('getNext')->willReturn($this->jobStub);
         $repositoryStub->method('delete')->willReturn(false);
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -384,7 +365,6 @@ class StoreTest extends TestCase
 
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
         $jobsStore->dequeue($this->jobStub->getType());
     }
 
@@ -399,7 +379,6 @@ class StoreTest extends TestCase
         $repositoryStub->method('getNext')->willReturn($this->jobStub);
         $repositoryStub->method('delete')->willReturnOnConsecutiveCalls(false, true);
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -410,7 +389,6 @@ class StoreTest extends TestCase
         );
         $jobsStore->runSetup();
 
-        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
         $this->assertNotNull($jobsStore->dequeue($this->jobStub->getType()));
     }
 
@@ -421,7 +399,6 @@ class StoreTest extends TestCase
      */
     public function testCanMarkFailedJob(): void
     {
-        /** @psalm-suppress InvalidArgument */
         $jobsStore = new Store(
             $this->moduleConfiguration,
             $this->loggerStub,
@@ -438,12 +415,10 @@ class StoreTest extends TestCase
 
         $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->markFailedJob($this->jobStub);
 
         $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
 
-        /** @psalm-suppress InvalidArgument */
         $jobsStore->markFailedJob($this->jobStub);
 
         $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne());
diff --git a/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php b/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php
index 03ee2d2..188a36a 100644
--- a/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php
+++ b/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php
@@ -26,19 +26,19 @@ use PHPUnit\Framework\TestCase;
 class RedisStoreTest extends TestCase
 {
     /**
-     * @var Stub|ModuleConfiguration
+     * @var Stub
      */
     protected $moduleConfigurationStub;
     /**
-     * @var MockObject|LoggerInterface
+     * @var MockObject
      */
     protected $loggerMock;
     /**
-     * @var MockObject|Redis
+     * @var MockObject
      */
     protected $redisMock;
     /**
-     * @var Stub|JobInterface
+     * @var Stub
      */
     protected $jobStub;
 
@@ -56,11 +56,9 @@ class RedisStoreTest extends TestCase
      */
     public function testCanCreateInstance(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             RedisStore::class,
             new RedisStore(
@@ -80,7 +78,6 @@ class RedisStoreTest extends TestCase
     {
         $this->expectException(InvalidConfigurationException::class);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             RedisStore::class,
             new RedisStore(
@@ -97,19 +94,15 @@ class RedisStoreTest extends TestCase
     {
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Error trying to connect to Redis DB.'));
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('connect')->willThrowException(new RedisException('test'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             RedisStore::class,
             new RedisStore(
@@ -126,19 +119,15 @@ class RedisStoreTest extends TestCase
     {
         $this->expectException(StoreException::class);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Error trying to set auth parameter for Redis.'));
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample', 'auth' => 'test']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('auth')->willThrowException(new RedisException('test'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             RedisStore::class,
             new RedisStore(
@@ -154,19 +143,15 @@ class RedisStoreTest extends TestCase
     public function testThrowsOnSetPrefixOptionError(): void
     {
         $this->expectException(StoreException::class);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Could not set key prefix for Redis.'));
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('setOption')->willThrowException(new RedisException('test'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertInstanceOf(
             RedisStore::class,
             new RedisStore(
@@ -184,18 +169,14 @@ class RedisStoreTest extends TestCase
      */
     public function testCanCallRPushMethod(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('isConnected')->willReturn(true);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->expects($this->once())
             ->method('rPush')
             ->with($this->stringStartsWith(RedisStore::LIST_KEY_JOB), $this->isType('string'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -204,25 +185,20 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore->enqueue($this->jobStub);
     }
 
     public function testThrowsOnRPushError(): void
     {
         $this->expectException(StoreException::class);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Could not add job to Redis list.'));
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('rPush')->willThrowException(new RedisException('test'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -231,7 +207,6 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore->enqueue($this->jobStub);
     }
 
@@ -240,15 +215,12 @@ class RedisStoreTest extends TestCase
      */
     public function testCanDequeueJob(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('lPop')
             ->willReturn(serialize($this->jobStub));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -257,27 +229,22 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument, MixedArgument, PossiblyUndefinedMethod */
         $this->assertInstanceOf(JobInterface::class, $redisStore->dequeue($this->jobStub->getType()));
     }
 
     public function testThrowsOnLPopError(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('lPop')
             ->willThrowException(new RedisException('test'));
 
         $this->expectException(StoreException::class);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Could not pop job from Redis list.'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -286,27 +253,22 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument, MixedArgument, PossiblyUndefinedMethod */
         $redisStore->dequeue($this->jobStub->getType());
     }
 
     public function testThrowsIfNotAbleToDeserializeJobEntry(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('lPop')
             ->willReturn('invalid');
 
         $this->expectException(StoreException::class);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Could not deserialize job entry which was available in Redis.'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -316,7 +278,6 @@ class RedisStoreTest extends TestCase
         );
 
         // Suppress notice being raised using @
-        /** @psalm-suppress PossiblyInvalidArgument, MixedArgument, PossiblyUndefinedMethod */
         @$redisStore->dequeue($this->jobStub->getType());
     }
 
@@ -325,16 +286,13 @@ class RedisStoreTest extends TestCase
      */
     public function testCanMarkFailedJob(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->expects($this->once())
             ->method('rPush')
             ->with($this->stringStartsWith(RedisStore::LIST_KEY_JOB_FAILED), $this->isType('string'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -343,27 +301,22 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore->markFailedJob($this->jobStub);
     }
 
     public function testThrowsOnMarkingFailedJobError(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->redisMock->method('rPush')
             ->willThrowException(new RedisException('test'));
 
         $this->expectException(StoreException::class);
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->loggerMock->expects($this->atLeastOnce())
             ->method('error')
             ->with($this->stringContains('Could not mark job as failed.'));
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -372,7 +325,6 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore->markFailedJob($this->jobStub);
     }
 
@@ -381,11 +333,9 @@ class RedisStoreTest extends TestCase
      */
     public function testSetupIsNotNeeded(): void
     {
-        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
         $this->moduleConfigurationStub->method('getConnectionParameters')
             ->willReturn(['host' => 'sample']);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $redisStore = new RedisStore(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -394,7 +344,6 @@ class RedisStoreTest extends TestCase
             $this->redisMock
         );
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $this->assertFalse($redisStore->needsSetup());
     }
 }
diff --git a/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php b/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php
index ebd98ad..9c51588 100644
--- a/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php
+++ b/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php
@@ -21,7 +21,7 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker
- * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
  * @uses \SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
@@ -30,29 +30,27 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
  * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
- * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\Hash
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
  * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
  * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
- *
- * @psalm-suppress all
  */
 class TrackerTest extends TestCase
 {
     /**
-     * @var Stub|ModuleConfiguration
+     * @var Stub
      */
     protected $moduleConfigurationStub;
     /**
-     * @var MockObject|LoggerInterface
+     * @var MockObject
      */
     protected $loggerMock;
     /**
-     * @var MockObject|Store
+     * @var MockObject
      */
     protected $dataStoreMock;
     /**
-     * @var Stub|HelpersManager
+     * @var Stub
      */
     protected $helpersManagerStub;
 
@@ -67,7 +65,6 @@ class TrackerTest extends TestCase
     }
 
     /**
-     * @psalm-suppress PossiblyInvalidArgument
      * @throws StoreException
      */
     public function testCanCreateInstance(): void
@@ -105,7 +102,6 @@ class TrackerTest extends TestCase
             ->method('persist')
             ->with($authenticationEventStub);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $tracker = new Tracker(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -129,7 +125,6 @@ class TrackerTest extends TestCase
         $this->dataStoreMock->expects($this->once())
             ->method('runSetup');
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $tracker = new Tracker(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -154,7 +149,6 @@ class TrackerTest extends TestCase
         $this->loggerMock->expects($this->once())
             ->method('warning');
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $tracker = new Tracker(
             $this->moduleConfigurationStub,
             $this->loggerMock,
@@ -176,7 +170,6 @@ class TrackerTest extends TestCase
             ->method('getConnectedOrganizations')
             ->willReturn($connectedOrganizationsBagStub);
 
-        /** @psalm-suppress PossiblyInvalidArgument */
         $tracker = new Tracker(
             $this->moduleConfigurationStub,
             $this->loggerMock,
diff --git a/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php b/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php
index a461223..f22f4bb 100644
--- a/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php
+++ b/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php
@@ -19,19 +19,17 @@ use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
 
 /**
  * @covers \SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder
- * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfiguration
  * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
- *
- * @psalm-suppress all
  */
 class AuthenticationDataTrackerBuilderTest extends TestCase
 {
     /**
-     * @var MockObject|LoggerInterface
+     * @var MockObject
      */
     protected $loggerMock;
     /**
-     * @var Stub|ModuleConfiguration
+     * @var Stub
      */
     protected $moduleConfigurationStub;
 
-- 
GitLab