diff --git a/public/assets/css/src/icons/no-image.svg b/public/assets/css/src/icons/no-image.svg
new file mode 100644
index 0000000000000000000000000000000000000000..37449107d892a49858f0d4c4855abfefe57755d7
--- /dev/null
+++ b/public/assets/css/src/icons/no-image.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:none;}</style></defs><title>no-image</title><path d="M30,3.4141,28.5859,2,2,28.5859,3.4141,30l2-2H26a2.0027,2.0027,0,0,0,2-2V5.4141ZM26,26H7.4141l7.7929-7.793,2.3788,2.3787a2,2,0,0,0,2.8284,0L22,19l4,3.9973Zm0-5.8318-2.5858-2.5859a2,2,0,0,0-2.8284,0L19,19.1682l-2.377-2.3771L26,7.4141Z"/><path d="M6,22V19l5-4.9966,1.3733,1.3733,1.4159-1.416-1.375-1.375a2,2,0,0,0-2.8284,0L6,16.1716V6H22V4H6A2.002,2.002,0,0,0,4,6V22Z"/><rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/></svg>
\ No newline at end of file
diff --git a/src/Entities/Bases/AbstractProvider.php b/src/Entities/Bases/AbstractProvider.php
index 9e63abde92dc28fc928e623ea3be29f2794de2fb..e02dc39e4b7fbc309668c79ae08f4c8e763204b0 100755
--- a/src/Entities/Bases/AbstractProvider.php
+++ b/src/Entities/Bases/AbstractProvider.php
@@ -6,35 +6,43 @@ namespace SimpleSAML\Module\accounting\Entities\Bases;
 
 use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
 use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
 
 abstract class AbstractProvider implements ProviderInterface
 {
     protected array $metadata;
+    protected HelpersManager $helpersManager;
     protected string $entityId;
 
-    public function __construct(array $metadata)
+    public function __construct(array $metadata, HelpersManager $helpersManager = null)
     {
         $this->metadata = $metadata;
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
         $this->entityId = $this->resolveEntityId();
     }
 
-    protected function resolveOptionallyLocalizedString(string $key, string $locale = 'en'): ?string
-    {
-        if (!isset($this->metadata[$key])) {
+    protected function resolveOptionallyLocalizedString(
+        string $key,
+        string $locale = self::DEFAULT_LOCALE,
+        array $metadataOverride = null
+    ): ?string {
+        $metadata = $metadataOverride ?? $this->metadata;
+
+        if (!isset($metadata[$key])) {
             return null;
         }
 
         // Check for non-localized version.
-        if (is_string($this->metadata[$key])) {
-            return $this->metadata[$key];
+        if (is_string($metadata[$key])) {
+            return $metadata[$key];
         }
 
         if (
-            is_array($this->metadata[$key]) &&
-            !empty($this->metadata[$key][$locale]) &&
-            is_string($this->metadata[$key][$locale])
+            is_array($metadata[$key]) &&
+            !empty($metadata[$key][$locale]) &&
+            is_string($metadata[$key][$locale])
         ) {
-            return $this->metadata[$key][$locale];
+            return $metadata[$key][$locale];
         }
 
         return null;
@@ -50,8 +58,10 @@ abstract class AbstractProvider implements ProviderInterface
         return $this->entityId;
     }
 
-    abstract public function getName(string $locale = 'en'): ?string;
-    abstract public function getDescription(string $locale = 'en'): ?string;
+    abstract public function getName(string $locale = self::DEFAULT_LOCALE): ?string;
+    abstract public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string;
+    abstract public function getLogoUrl(): ?string;
     abstract protected function resolveEntityId(): string;
     abstract public function getProtocol(): AuthenticationProtocolInterface;
+    abstract protected function getProviderDescription(): string;
 }
diff --git a/src/Entities/Interfaces/ProviderInterface.php b/src/Entities/Interfaces/ProviderInterface.php
index c82a1792698873b1ba3e295addba031708832ca4..259db355e48fa85e7efd7915a3174045880a4c0d 100755
--- a/src/Entities/Interfaces/ProviderInterface.php
+++ b/src/Entities/Interfaces/ProviderInterface.php
@@ -9,9 +9,12 @@ use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
 
 interface ProviderInterface
 {
+    public const DEFAULT_LOCALE = 'en';
+
     public function getMetadata(): array;
-    public function getName(string $locale = 'en'): ?string;
+    public function getName(string $locale = self::DEFAULT_LOCALE): ?string;
     public function getEntityId(): string;
-    public function getDescription(string $locale = 'en'): ?string;
+    public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string;
+    public function getLogoUrl(): ?string;
     public function getProtocol(): AuthenticationProtocolInterface;
 }
diff --git a/src/Entities/Providers/Bases/AbstractOidcProvider.php b/src/Entities/Providers/Bases/AbstractOidcProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..5c1e73eeeb10b4d0f22cc31cd1eee16e566f0e54
--- /dev/null
+++ b/src/Entities/Providers/Bases/AbstractOidcProvider.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Providers\Bases;
+
+use SimpleSAML\Module\accounting\Entities\Authentication;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+
+abstract class AbstractOidcProvider extends AbstractProvider
+{
+    public const METADATA_KEY_LOGO_URI = 'logo_uri';
+
+    abstract public function getName(string $locale = self::DEFAULT_LOCALE): ?string;
+    abstract public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string;
+    abstract protected function resolveEntityId(): string;
+    abstract protected function getProviderDescription(): string;
+
+    public function getLogoUrl(): ?string
+    {
+        if (
+            !empty($this->metadata[self::METADATA_KEY_LOGO_URI]) &&
+            is_string($this->metadata[self::METADATA_KEY_LOGO_URI])
+        ) {
+            return $this->metadata[self::METADATA_KEY_LOGO_URI];
+        }
+
+        return null;
+    }
+
+    public function getProtocol(): AuthenticationProtocolInterface
+    {
+        return new Authentication\Protocol\Oidc();
+    }
+}
diff --git a/src/Entities/Providers/Bases/AbstractSaml2Provider.php b/src/Entities/Providers/Bases/AbstractSaml2Provider.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ffbdca60813796319520ac1b9d7a30e677e22b3
--- /dev/null
+++ b/src/Entities/Providers/Bases/AbstractSaml2Provider.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Providers\Bases;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+use SimpleSAML\Module\accounting\Entities\Authentication;
+
+abstract class AbstractSaml2Provider extends AbstractProvider
+{
+    public const METADATA_KEY_ENTITY_ID = 'entityid';
+    public const METADATA_KEY_NAME = 'name';
+    public const METADATA_KEY_DESCRIPTION = 'description';
+    public const METADATA_KEY_UI_INFO = 'UIInfo';
+    public const METADATA_KEY_UI_INFO_DESCRIPTION = 'Description';
+    public const METADATA_KEY_UI_INFO_DISPLAY_NAME = 'DisplayName';
+    public const METADATA_KEY_UI_INFO_LOGO = 'Logo';
+    public const METADATA_KEY_UI_INFO_LOGO_URL = 'url';
+
+    protected function getEntityInfoString(string $key, string $locale = self::DEFAULT_LOCALE): ?string
+    {
+        return $this->resolveOptionallyLocalizedString($key, $locale);
+    }
+
+    protected function getEntityUiInfoString(string $key, string $locale = self::DEFAULT_LOCALE): ?string
+    {
+        if (
+            isset($this->metadata[self::METADATA_KEY_UI_INFO]) &&
+            is_array($this->metadata[self::METADATA_KEY_UI_INFO])
+        ) {
+            return $this->resolveOptionallyLocalizedString(
+                $key,
+                $locale,
+                $this->metadata[self::METADATA_KEY_UI_INFO]
+            );
+        }
+
+        return null;
+    }
+
+    public function getName(string $locale = self::DEFAULT_LOCALE): ?string
+    {
+        return $this->getEntityInfoString(self::METADATA_KEY_NAME, $locale) ??
+            $this->getEntityUiInfoString(self::METADATA_KEY_UI_INFO_DISPLAY_NAME, $locale);
+    }
+
+    public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string
+    {
+        return $this->getEntityInfoString(self::METADATA_KEY_DESCRIPTION, $locale) ??
+            $this->getEntityUiInfoString(self::METADATA_KEY_UI_INFO_DESCRIPTION, $locale);
+    }
+
+    public function getLogoUrl(): ?string
+    {
+        $logoElement = $this->helpersManager->getArr()->getNestedElementByKey(
+            $this->metadata,
+            self::METADATA_KEY_UI_INFO,
+            self::METADATA_KEY_UI_INFO_LOGO,
+            0,
+            self::METADATA_KEY_UI_INFO_LOGO_URL
+        );
+
+        if (!is_array($logoElement)) {
+            return null;
+        }
+
+        /** @var mixed $logoUrl */
+        $logoUrl = current($logoElement);
+
+        if (is_string($logoUrl) && filter_var($logoUrl, FILTER_VALIDATE_URL)) {
+            return $logoUrl;
+        }
+
+        return null;
+    }
+
+    /**
+     * @throws MetadataException
+     */
+    protected function resolveEntityId(): string
+    {
+        if (empty($entityId = $this->getEntityInfoString(self::METADATA_KEY_ENTITY_ID))) {
+            $message = sprintf('Provider metadata does not contain entity ID (%s).', $this->getProviderDescription());
+            throw new MetadataException($message);
+        }
+
+        return $entityId;
+    }
+
+    public function getProtocol(): AuthenticationProtocolInterface
+    {
+        return new Authentication\Protocol\Saml2();
+    }
+}
diff --git a/src/Entities/Providers/Identity/Oidc.php b/src/Entities/Providers/Identity/Oidc.php
index c662f78753be98476d0c03d8086fb94a0dafa24b..0ead0e2b14903484b8f7a2c3a47dbd584cdb2a72 100755
--- a/src/Entities/Providers/Identity/Oidc.php
+++ b/src/Entities/Providers/Identity/Oidc.php
@@ -4,13 +4,11 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Entities\Providers\Identity;
 
-use SimpleSAML\Module\accounting\Entities\Authentication;
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
-use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
 use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider;
 use SimpleSAML\Module\accounting\Exceptions\MetadataException;
 
-class Oidc extends AbstractProvider implements IdentityProviderInterface
+class Oidc extends AbstractOidcProvider implements IdentityProviderInterface
 {
     public const METADATA_KEY_ENTITY_ID = 'issuer';
 
@@ -36,11 +34,11 @@ class Oidc extends AbstractProvider implements IdentityProviderInterface
             return $this->metadata[self::METADATA_KEY_ENTITY_ID];
         }
 
-        throw new MetadataException('OpenID VersionedDataProvider metadata does not contain entity ID.');
+        throw new MetadataException($this->getProviderDescription() . ' metadata does not contain entity ID.');
     }
 
-    public function getProtocol(): AuthenticationProtocolInterface
+    protected function getProviderDescription(): string
     {
-        return new Authentication\Protocol\Oidc();
+        return $this->getProtocol()->getDesignation() . ' OpenID Provider';
     }
 }
diff --git a/src/Entities/Providers/Identity/Saml2.php b/src/Entities/Providers/Identity/Saml2.php
index 04768636840af510618c96d26587f396b283afe4..8bef30d9a6a930bac920b202f27e8d3e90a13afa 100755
--- a/src/Entities/Providers/Identity/Saml2.php
+++ b/src/Entities/Providers/Identity/Saml2.php
@@ -5,44 +5,15 @@ declare(strict_types=1);
 namespace SimpleSAML\Module\accounting\Entities\Providers\Identity;
 
 use SimpleSAML\Module\accounting\Entities\Authentication;
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
 use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
 use SimpleSAML\Module\accounting\Entities\Interfaces\IdentityProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider;
 use SimpleSAML\Module\accounting\Exceptions\MetadataException;
 
-class Saml2 extends AbstractProvider implements IdentityProviderInterface
+class Saml2 extends AbstractSaml2Provider 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.');
-    }
-
-    public function getProtocol(): AuthenticationProtocolInterface
+    protected function getProviderDescription(): string
     {
-        return new Authentication\Protocol\Saml2();
+        return $this->getProtocol()->getDesignation() . ' Identity Provider';
     }
 }
diff --git a/src/Entities/Providers/Service/Oidc.php b/src/Entities/Providers/Service/Oidc.php
index 5f5ff82477128169db5708b40932172d79b54a6d..10cb0300be2a4d12985f64f6bde1060570f5a28a 100755
--- a/src/Entities/Providers/Service/Oidc.php
+++ b/src/Entities/Providers/Service/Oidc.php
@@ -4,13 +4,11 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Entities\Providers\Service;
 
-use SimpleSAML\Module\accounting\Entities\Authentication;
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
-use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
 use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider;
 use SimpleSAML\Module\accounting\Exceptions\MetadataException;
 
-class Oidc extends AbstractProvider implements ServiceProviderInterface
+class Oidc extends AbstractOidcProvider implements ServiceProviderInterface
 {
     public const METADATA_KEY_ENTITY_ID = 'id';
     public const METADATA_KEY_NAME = 'name';
@@ -38,11 +36,11 @@ class Oidc extends AbstractProvider implements ServiceProviderInterface
             return $this->metadata[self::METADATA_KEY_ENTITY_ID];
         }
 
-        throw new MetadataException('Relying VersionedDataProvider metadata does not contain entity ID.');
+        throw new MetadataException($this->getProviderDescription() . ' metadata does not contain entity ID.');
     }
 
-    public function getProtocol(): AuthenticationProtocolInterface
+    protected function getProviderDescription(): string
     {
-        return new Authentication\Protocol\Oidc();
+        return $this->getProtocol()->getDesignation() . ' Relying Party';
     }
 }
diff --git a/src/Entities/Providers/Service/Saml2.php b/src/Entities/Providers/Service/Saml2.php
index d0dfd4ac065c2b22a7f3dcdcf82c14096981f40d..deeb30727e3c05b0446c315b726a73923321c9c1 100755
--- a/src/Entities/Providers/Service/Saml2.php
+++ b/src/Entities/Providers/Service/Saml2.php
@@ -4,45 +4,13 @@ declare(strict_types=1);
 
 namespace SimpleSAML\Module\accounting\Entities\Providers\Service;
 
-use SimpleSAML\Module\accounting\Entities\Authentication;
-use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
-use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
 use SimpleSAML\Module\accounting\Entities\Interfaces\ServiceProviderInterface;
-use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider;
 
-class Saml2 extends AbstractProvider implements ServiceProviderInterface
+class Saml2 extends AbstractSaml2Provider 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.');
-    }
-
-    public function getProtocol(): AuthenticationProtocolInterface
+    protected function getProviderDescription(): string
     {
-        return new Authentication\Protocol\Saml2();
+        return $this->getProtocol()->getDesignation() . ' Service Provider';
     }
 }
diff --git a/src/Helpers/Arr.php b/src/Helpers/Arr.php
index 465e122ad3de3e8d9f57aed34b8c8e3494d3678c..061461f1a228b83391a24c445efdd0c4ab1932ec 100755
--- a/src/Helpers/Arr.php
+++ b/src/Helpers/Arr.php
@@ -37,4 +37,33 @@ class Arr
         $keys = array_keys($array);
         return $keys !== array_keys($keys);
     }
+
+    /**
+     * @param array $array
+     * @param  string|int  ...$keys
+     * @return array|null
+     */
+    public function getNestedElementByKey(array $array, ...$keys): ?array
+    {
+        $element = $array;
+
+        foreach ($keys as $key) {
+            if (!is_array($element)) {
+                return null;
+            }
+
+            if (!isset($element[$key])) {
+                return null;
+            }
+
+            /** @var mixed $element */
+            $element = $element[$key];
+        }
+
+        if (is_array($element)) {
+            return $element;
+        }
+
+        return [$element];
+    }
 }
diff --git a/templates/user/connected-organizations.twig b/templates/user/connected-organizations.twig
index 6bbbf8a4c2966de007cb4c13e1372bd453adf052..3e8e3afb5140bb30f6ffde8a024327c0f39708b0 100755
--- a/templates/user/connected-organizations.twig
+++ b/templates/user/connected-organizations.twig
@@ -20,7 +20,14 @@
 
         {% for connectedServiceProvider in connectedServiceProviderBag.getAll %}
             <tr id="connected-service-provider-{{ loop.index }}">
-                <td>{{ connectedServiceProvider.getServiceProvider.getName|e }}</td>
+                <td>
+                    <img src="{{ connectedServiceProvider.serviceProvider.logoUrl ?? asset('css/src/icons/no-image.svg', 'accounting') }}"
+                         width="30"
+                         height="30"
+                         loading="lazy"
+                         alt="Service Logo"/>
+                    {{ connectedServiceProvider.getServiceProvider.getName|e }}
+                </td>
                 <td>{{ connectedServiceProvider.getNumberOfAuthentications|e }}</td>
                 <td>{{ connectedServiceProvider.getLastAuthenticationAt|date() }}</td>
             </tr>
diff --git a/tests/src/Constants/StateArrays.php b/tests/src/Constants/StateArrays.php
index 1833f187400ec15444a6d5cd5ae2cdba4e3a4f31..8b4b425b056a7c2141e6e20ea519b5fafda2386b 100755
--- a/tests/src/Constants/StateArrays.php
+++ b/tests/src/Constants/StateArrays.php
@@ -44,7 +44,22 @@ final class StateArrays
             'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
             'metadata-set' => 'saml20-sp-remote',
             'name' => 'Test service',
-            'description' => 'Test service description'
+            'description' => 'Test service description',
+            'UIInfo' => [
+                'DisplayName' => [
+                    'en' => 'Test service UiInfo',
+                ],
+                'Description' => [
+                    'en' => 'Test service description UiInfo',
+                ],
+                'Logo' => [
+                    [
+                        'url' => 'https://placehold.co/100x80/orange/white?text=test',
+                        'height' => 80,
+                        'width' => 100,
+                    ],
+                ],
+            ],
         ],
         'saml:RelayState' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/admin/test/default-sp',
         'saml:RequestId' => null,
@@ -117,6 +132,21 @@ final class StateArrays
             'entityid' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
             'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
             'metadata-set' => 'saml20-sp-remote',
+            'UIInfo' => [
+                'DisplayName' => [
+                    'en' => 'Test service UiInfo',
+                ],
+                'Description' => [
+                    'en' => 'Test service description UiInfo',
+                ],
+                'Logo' => [
+                    [
+                        'url' => 'https://placehold.co/100x80/orange/white?text=test',
+                        'height' => 80,
+                        'width' => 100,
+                    ],
+                ],
+            ],
         ],
         'Source' => [
             'host' => 'localhost.someone.from.hr',
@@ -219,6 +249,7 @@ final class StateArrays
                 'owner' => null,
                 'post_logout_redirect_uri' => [],
                 'backchannel_logout_uri' => 'http://sp.host.internal:8074/logout.php',
+                'logo_uri' => 'http://sp.host.internal:8074/logo.svg',
             ],
             'AuthorizationRequestParameters' => [
                 'response_type' => 'code',
diff --git a/tests/src/Entities/Bases/AbstractProviderTest.php b/tests/src/Entities/Bases/AbstractProviderTest.php
index e8d8a2743b4492f6242c9ae8aa5b162bc8cead90..aae51bd5093d34fa7a257d5cd209e4628b873057 100755
--- a/tests/src/Entities/Bases/AbstractProviderTest.php
+++ b/tests/src/Entities/Bases/AbstractProviderTest.php
@@ -112,6 +112,16 @@ class AbstractProviderTest extends TestCase
                     }
                 };
             }
+
+            protected function getProviderDescription(): string
+            {
+                return 'provider description';
+            }
+
+            public function getLogoUrl(): ?string
+            {
+                return 'https://example.org/logo';
+            }
         };
     }
 }
diff --git a/tests/src/Entities/Providers/Bases/AbstractOidcProviderTest.php b/tests/src/Entities/Providers/Bases/AbstractOidcProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..40dc7dccee1875fec35515ed9c29371a4a8c6531
--- /dev/null
+++ b/tests/src/Entities/Providers/Bases/AbstractOidcProviderTest.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Providers\Bases;
+
+use PHPUnit\Framework\MockObject\Stub;
+use SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc;
+use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Helpers\Arr;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class AbstractOidcProviderTest extends TestCase
+{
+    protected Stub $helpersManagerStub;
+    protected Stub $arrStub;
+    protected array $metadata;
+
+    protected function setUp(): void
+    {
+        $this->helpersManagerStub = $this->createStub(HelpersManager::class);
+        $this->arrStub = $this->createStub(Arr::class);
+        $this->metadata = StateArrays::OIDC_FULL['Oidc']['RelyingPartyMetadata'];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(AbstractOidcProvider::class, $this->prepareInstance(StateArrays::OIDC_FULL));
+    }
+
+    public function testCanGetLogoUrl(): void
+    {
+        $this->assertSame(
+            $this->metadata['logo_uri'],
+            $this->prepareInstance($this->metadata)->getLogoUrl()
+        );
+
+        $metadaNoLogo = $this->metadata;
+        unset($metadaNoLogo['logo_uri']);
+
+        $this->assertNull($this->prepareInstance($metadaNoLogo)->getLogoUrl());
+    }
+
+    public function testCanGetProtocol(): void
+    {
+        $this->assertInstanceOf(Oidc::class, $this->prepareInstance($this->metadata)->getProtocol());
+    }
+
+    protected function prepareInstance(array $metadata): AbstractOidcProvider
+    {
+        $this->helpersManagerStub->method('getArr')->willReturn($this->arrStub);
+
+        return new class ($metadata, $this->helpersManagerStub) extends AbstractOidcProvider {
+            public function getName(string $locale = self::DEFAULT_LOCALE): ?string
+            {
+                return 'name';
+            }
+
+            public function getDescription(string $locale = self::DEFAULT_LOCALE): ?string
+            {
+                return 'description';
+            }
+
+            protected function resolveEntityId(): string
+            {
+                return 'entityId';
+            }
+
+            protected function getProviderDescription(): string
+            {
+                return 'provider description';
+            }
+        };
+    }
+}
diff --git a/tests/src/Entities/Providers/Bases/AbstractSaml2ProviderTest.php b/tests/src/Entities/Providers/Bases/AbstractSaml2ProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0822ec2bbda16b5fbc9eee41e08c443c54ac9bc0
--- /dev/null
+++ b/tests/src/Entities/Providers/Bases/AbstractSaml2ProviderTest.php
@@ -0,0 +1,136 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Providers\Bases;
+
+use PHPUnit\Framework\MockObject\Stub;
+use SimpleSAML\Module\accounting\Entities\Interfaces\AuthenticationProtocolInterface;
+use SimpleSAML\Module\accounting\Entities\Interfaces\ProviderInterface;
+use SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Exceptions\MetadataException;
+use SimpleSAML\Module\accounting\Helpers\Arr;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class AbstractSaml2ProviderTest extends TestCase
+{
+    protected Stub $helpersManagerStub;
+    protected Stub $arrStub;
+    protected array $metadata;
+
+    protected function setUp(): void
+    {
+        $this->helpersManagerStub = $this->createStub(HelpersManager::class);
+        $this->arrStub = $this->createStub(Arr::class);
+        $this->metadata = StateArrays::SAML2_FULL['SPMetadata'];
+    }
+
+    protected function prepareInstance(array $metadata): AbstractSaml2Provider
+    {
+        $this->helpersManagerStub->method('getArr')->willReturn($this->arrStub);
+
+        return new class ($metadata, $this->helpersManagerStub) extends AbstractSaml2Provider {
+            protected function getProviderDescription(): string
+            {
+                return 'service description';
+            }
+        };
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(AbstractSaml2Provider::class, $this->prepareInstance($this->metadata));
+    }
+
+    public function testCanGetName(): void
+    {
+        $metadata = $this->metadata;
+        $this->assertSame(
+            $this->metadata[AbstractSaml2Provider::METADATA_KEY_NAME],
+            $this->prepareInstance($metadata)->getName()
+        );
+
+        unset($metadata[AbstractSaml2Provider::METADATA_KEY_NAME]);
+        $this->assertSame(
+            $this->metadata[AbstractSaml2Provider::METADATA_KEY_UI_INFO]
+                [AbstractSaml2Provider::METADATA_KEY_UI_INFO_DISPLAY_NAME]
+                [ProviderInterface::DEFAULT_LOCALE],
+            $this->prepareInstance($metadata)->getName()
+        );
+
+        unset($metadata[AbstractSaml2Provider::METADATA_KEY_UI_INFO]);
+        $this->assertNull($this->prepareInstance($metadata)->getName());
+    }
+
+    public function testCanGetDescription(): void
+    {
+        $metadata = $this->metadata;
+        $this->assertSame(
+            $this->metadata[AbstractSaml2Provider::METADATA_KEY_DESCRIPTION],
+            $this->prepareInstance($metadata)->getDescription()
+        );
+
+        unset($metadata[AbstractSaml2Provider::METADATA_KEY_DESCRIPTION]);
+        $this->assertSame(
+            $this->metadata[AbstractSaml2Provider::METADATA_KEY_UI_INFO]
+            [AbstractSaml2Provider::METADATA_KEY_UI_INFO_DESCRIPTION]
+            [ProviderInterface::DEFAULT_LOCALE],
+            $this->prepareInstance($metadata)->getDescription()
+        );
+
+        unset($metadata[AbstractSaml2Provider::METADATA_KEY_UI_INFO]);
+        $this->assertNull($this->prepareInstance($metadata)->getDescription());
+    }
+
+    public function testCanGetLogo(): void
+    {
+        $this->arrStub->method('getNestedElementByKey')->willReturn(['https://example.org/logo']);
+
+        $this->assertSame(
+            'https://example.org/logo',
+            $this->prepareInstance($this->metadata)->getLogoUrl()
+        );
+    }
+
+    public function testGetLogoNotFound(): void
+    {
+        $this->arrStub->method('getNestedElementByKey')->willReturn(null);
+
+        $this->assertNull(
+            $this->prepareInstance($this->metadata)->getLogoUrl()
+        );
+    }
+
+    public function testGetLogoIsNullIfNotValid(): void
+    {
+        $this->arrStub->method('getNestedElementByKey')->willReturn(['not-valid']);
+
+        $this->assertNull(
+            $this->prepareInstance($this->metadata)->getLogoUrl()
+        );
+    }
+
+    public function testThrowsForInvalidEntityId(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[AbstractSaml2Provider::METADATA_KEY_ENTITY_ID]);
+
+        $this->expectException(MetadataException::class);
+
+        $this->prepareInstance($metadata);
+    }
+
+    public function testCanGetProtocol(): void
+    {
+        $this->assertInstanceOf(
+            AuthenticationProtocolInterface::class,
+            $this->prepareInstance($this->metadata)->getProtocol()
+        );
+    }
+}
diff --git a/tests/src/Entities/Providers/Identity/OidcTest.php b/tests/src/Entities/Providers/Identity/OidcTest.php
index 91ab3e260936ecdbb74d3c17d9da8a6130916141..32591e217a0a4c2d3d28c8e660d8396bb7708d8c 100755
--- a/tests/src/Entities/Providers/Identity/OidcTest.php
+++ b/tests/src/Entities/Providers/Identity/OidcTest.php
@@ -11,6 +11,8 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException;
 /**
  * @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc
  */
 class OidcTest extends TestCase
 {
diff --git a/tests/src/Entities/Providers/Identity/Saml2Test.php b/tests/src/Entities/Providers/Identity/Saml2Test.php
index 7c995952a1fee1d1a238a78853682c393d655c6f..5c4db09f39ab25ac6fabe0066dc9d6aa76e15e17 100755
--- a/tests/src/Entities/Providers/Identity/Saml2Test.php
+++ b/tests/src/Entities/Providers/Identity/Saml2Test.php
@@ -12,6 +12,8 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
 /**
  * @covers \SimpleSAML\Module\accounting\Entities\Providers\Identity\Saml2
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2
  */
 class Saml2Test extends TestCase
 {
diff --git a/tests/src/Entities/Providers/Service/OidcTest.php b/tests/src/Entities/Providers/Service/OidcTest.php
index db62ad41c0a6337284d72342876b4e478248d3bc..dbba56c8fed584fb7ed1feb2126b08d4d84bef44 100755
--- a/tests/src/Entities/Providers/Service/OidcTest.php
+++ b/tests/src/Entities/Providers/Service/OidcTest.php
@@ -11,6 +11,8 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException;
 /**
  * @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc
  */
 class OidcTest extends TestCase
 {
diff --git a/tests/src/Entities/Providers/Service/Saml2Test.php b/tests/src/Entities/Providers/Service/Saml2Test.php
index c4475d7089d65d70742a6b2b14d65b0860f72316..225c92ab25da2ff79911036270f30ce651c88f26 100755
--- a/tests/src/Entities/Providers/Service/Saml2Test.php
+++ b/tests/src/Entities/Providers/Service/Saml2Test.php
@@ -9,6 +9,8 @@ use SimpleSAML\Module\accounting\Exceptions\MetadataException;
 /**
  * @covers \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2
  * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2
  */
 class Saml2Test extends TestCase
 {
diff --git a/tests/src/Helpers/ArrayTest.php b/tests/src/Helpers/ArrayTest.php
index dc35b097da155765d5f25dc94fa382e18091e05a..2ad8905cc1236493d8ee658dc0f490c005f64a0f 100755
--- a/tests/src/Helpers/ArrayTest.php
+++ b/tests/src/Helpers/ArrayTest.php
@@ -70,4 +70,37 @@ class ArrayTest extends TestCase
         $this->assertTrue((new Arr())->isAssociative($associative));
         $this->assertTrue((new Arr())->isAssociative($mixed));
     }
+
+    public function testGetNestedElementByKey(): void
+    {
+        $simpleIndexed = [1, 2, 3];
+        $nestedIndexed = [[1, [2, [4, [5]]]], [3, 4]];
+        $nestedAssociative = ['a' => ['b' => 'c'], 'd' => 'e'];
+
+        $arrHelper = new Arr();
+
+        $this->assertSame($arrHelper->getNestedElementByKey($simpleIndexed, 0), [1]);
+        $this->assertNull($arrHelper->getNestedElementByKey($simpleIndexed, 3));
+        $this->assertNull($arrHelper->getNestedElementByKey($simpleIndexed, 'a'));
+        $this->assertNull($arrHelper->getNestedElementByKey($simpleIndexed, 0, 'a'));
+
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0), [1, [2, [4, [5]]]]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0), [1, [2, [4, [5]]]]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 0), [1]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1), [2, [4, [5]]]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 0), [2]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 1), [4, [5]]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 1, 0), [4]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 0, 1, 1, 1), [5]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 1), [3, 4]);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedIndexed, 1, 0), [3]);
+        $this->assertNull($arrHelper->getNestedElementByKey($nestedIndexed, 3));
+        $this->assertNull($arrHelper->getNestedElementByKey($nestedIndexed, 'a'));
+
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedAssociative, 'a'), ['b' => 'c']);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedAssociative, 'a', 'b'), ['c']);
+        $this->assertSame($arrHelper->getNestedElementByKey($nestedAssociative, 'd'), ['e']);
+        $this->assertNull($arrHelper->getNestedElementByKey($nestedAssociative, 3));
+        $this->assertNull($arrHelper->getNestedElementByKey($nestedAssociative, 'f'));
+    }
 }
diff --git a/tests/src/Helpers/ProviderResolverTest.php b/tests/src/Helpers/ProviderResolverTest.php
index 3661701b49175bb33f0e00568a2dbbd82b0fe60c..854e1af69375e87281c090ef48f6f4e63d879a68 100755
--- a/tests/src/Helpers/ProviderResolverTest.php
+++ b/tests/src/Helpers/ProviderResolverTest.php
@@ -21,6 +21,10 @@ use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
  * @uses \SimpleSAML\Module\accounting\Entities\Providers\Identity\Oidc
  * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Saml2
  * @uses \SimpleSAML\Module\accounting\Entities\Providers\Service\Oidc
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractSaml2Provider
+ * @uses \SimpleSAML\Module\accounting\Entities\Providers\Bases\AbstractOidcProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Saml2
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Protocol\Oidc
  */
 class ProviderResolverTest extends TestCase
 {