diff --git a/.gitignore b/.gitignore
index b3d340206b2dbe7e2dfa3a583bcc3793b8006962..b44d1332963c68308ef9274c9ab090dcf8ae17a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,6 @@ dist/
 *venv/
 .vscode/
 _version.py
+*.xml
+.coverage
+htmlcov
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 741ca8aa049dc553f77b89d803723671c06b86ca..517425cc82790d5a10b8cfa1561c6f3dad1e8c82 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -35,30 +35,46 @@ pylint:
     - pip install pylint
     - pylint dinamis_sdk tests
 
-
-OAuth2 Tests:
+Tests:
   extends: .tests_base
   script:
-    - python tests/test_spot_6_7_drs.py
-    - python tests/test_super_s2.py
-    - python tests/test_push.py
-    - python tests/test_headers.py authorization
+    - pip install coverage
 
-API key Tests:
-  extends: .tests_base
-  script:
+    - echo "Starting OAuth2 tests"
+    - coverage run -a tests/test_spot_6_7_drs.py
+    - coverage run -a tests/test_super_s2.py
+    - coverage run -a tests/test_push.py
+    - coverage run -a tests/test_misc.py
+    - coverage run -a tests/test_headers.py authorization
+
+    - echo "Starting API key tests"
     - dinamis_cli register
-    - python tests/test_headers.py access-key
+    - coverage run -a tests/test_headers.py access-key
     # ensure that we une only API key from now
     - mv /root/.config/dinamis_sdk_auth/.jwt /root/.config/dinamis_sdk_auth/.jwt_
-    - python tests/test_spot_6_7_drs.py
-    - python tests/test_super_s2.py
-    - python tests/test_push.py
+    - coverage run -a tests/test_misc.py
+    - coverage run -a tests/test_spot_6_7_drs.py
+    - coverage run -a tests/test_super_s2.py
+    - coverage run -a tests/test_push.py
     # Test API key from environment variables
     - export DINAMIS_SDK_ACCESS_KEY=$(cat /root/.config/dinamis_sdk_auth/.apikey | cut -d'"' -f4)
     - export DINAMIS_SDK_SECRET_KEY=$(cat /root/.config/dinamis_sdk_auth/.apikey | cut -d'"' -f8)
     - rm /root/.config/dinamis_sdk_auth/.apikey  # ensure that we use env. vars.
-    - python tests/test_spot_6_7_drs.py
+    - coverage run -a tests/test_spot_6_7_drs.py
     # bring back oauth2 credentials so we can revoke the API key
     - mv /root/.config/dinamis_sdk_auth/.jwt_ /root/.config/dinamis_sdk_auth/.jwt
     - dinamis_cli revoke ${DINAMIS_SDK_ACCESS_KEY}
+
+    - coverage report
+    - coverage xml
+    - coverage html
+  coverage: '/^TOTAL.+?(\d+\%)$/'
+  artifacts:
+    paths:
+      - htmlcov/
+    when: always
+    reports:
+      coverage_report:
+        coverage_format: cobertura
+        path: coverage.xml
+
diff --git a/dinamis_sdk/__init__.py b/dinamis_sdk/__init__.py
index 3d58f795aaa26390f9bc93f49d3293134ecec30a..2d20a647fbe350d940e8d28a2b7bd05fda3a488b 100644
--- a/dinamis_sdk/__init__.py
+++ b/dinamis_sdk/__init__.py
@@ -14,7 +14,7 @@ from dinamis_sdk.signing import (
 )  # noqa
 from .oauth2 import OAuth2Session  # noqa
 from .upload import push
-from .http import get_headers
+from .http import get_headers, get_userinfo
 
 try:
     __version__ = version("dinamis_sdk")
diff --git a/dinamis_sdk/http.py b/dinamis_sdk/http.py
index 37c0ac3c21b4244f2621aca333c231b4c8735494..9ab1160f7e17dd67526f5ba15271b0b812dd30fd 100644
--- a/dinamis_sdk/http.py
+++ b/dinamis_sdk/http.py
@@ -1,12 +1,12 @@
 """HTTP connections with various methods."""
 
-from typing import Dict
+from typing import Dict, Any
 from ast import literal_eval
 from pydantic import BaseModel, ConfigDict
 from .utils import get_logger_for, create_session
-from .oauth2 import OAuth2Session
+from .oauth2 import OAuth2Session, retrieve_token_endpoint
 from .model import ApiKey
-from .settings import ENV, SIGNING_ENDPOINT
+from .settings import ENV
 
 
 log = get_logger_for(__name__)
@@ -16,7 +16,7 @@ class BareConnectionMethod(BaseModel):
     """Bare connection method, no extra headers."""
 
     model_config = ConfigDict(arbitrary_types_allowed=True)
-    endpoint: str = SIGNING_ENDPOINT
+    endpoint: str = ENV.dinamis_sdk_signing_endpoint
 
     def get_headers(self) -> Dict[str, str]:
         """Get the headers."""
@@ -40,6 +40,13 @@ class OAuth2ConnectionMethod(BareConnectionMethod):
         """Return the headers."""
         return {"authorization": f"bearer {self.oauth2_session.get_access_token()}"}
 
+    def get_userinfo(self):
+        """Get the userinfo endpoint."""
+        openapi_url = retrieve_token_endpoint().replace("/token", "/userinfo")
+
+        _session = create_session()
+        return _session.get(openapi_url, timeout=10, headers=self.get_headers()).json()
+
 
 class ApiKeyConnectionMethod(BareConnectionMethod):
     """API key connection method."""
@@ -50,6 +57,10 @@ class ApiKeyConnectionMethod(BareConnectionMethod):
         """Return the headers."""
         return self.api_key.to_dict()
 
+    def get_userinfo(self):
+        """User info method for API key. Not available."""
+        raise NotImplementedError("No userinfo available with API key method.")
+
 
 class HTTPSession:
     """HTTP session class."""
@@ -78,9 +89,9 @@ class HTTPSession:
     def prepare_connection_method(self):
         """Set the connection method."""
         # Custom server without authentication method
-        if ENV.dinamis_sdk_bypass_auth_api:
+        if ENV.dinamis_sdk_digning_disable_auth:
             self._method = BareConnectionMethod(
-                endpoint=ENV.dinamis_sdk_bypass_auth_api
+                endpoint=ENV.dinamis_sdk_signing_endpoint
             )
 
         # API key method
@@ -110,6 +121,11 @@ class HTTPSession:
 session = HTTPSession()
 
 
-def get_headers():
-    """Return the headers."""
+def get_headers() -> dict[str, Any]:
+    """Return the headers needed to authenticate on the system."""
     return session.get_method().get_headers()
+
+
+def get_userinfo() -> dict[str, str]:
+    """Return userinfo."""
+    return OAuth2ConnectionMethod().get_userinfo()
diff --git a/dinamis_sdk/oauth2.py b/dinamis_sdk/oauth2.py
index 5469da4a861c84a8d60a6a9aae81904a22813c6a..92338cbc7e999c6787fcead6c754fe6399f1389b 100644
--- a/dinamis_sdk/oauth2.py
+++ b/dinamis_sdk/oauth2.py
@@ -8,14 +8,14 @@ from typing import Dict
 import qrcode  # type: ignore
 from .utils import create_session, get_logger_for
 from .model import JWT, DeviceGrantResponse
-from .settings import SIGNING_ENDPOINT
+from .settings import ENV
 
 log = get_logger_for(__name__)
 
 
 def retrieve_token_endpoint():
     """Retrieve the token endpoint from the s3 signing endpoint."""
-    openapi_url = SIGNING_ENDPOINT + "openapi.json"
+    openapi_url = ENV.dinamis_sdk_signing_endpoint + "openapi.json"
     log.debug("Fetching OAuth2 endpoint from openapi url %s", openapi_url)
     _session = create_session()
     res = _session.get(
@@ -55,6 +55,16 @@ class GrantMethodBase:
             "scope": "openid offline_access",
         }
 
+    def get_userinfo(self):
+        """Get the userinfo endpoint."""
+        if not self._token_endpoint:
+            self._token_endpoint = retrieve_token_endpoint()
+        openapi_url = retrieve_token_endpoint().replace("/token", "/userinfo")
+
+        _session = create_session()
+        res = _session.get(openapi_url, timeout=10, headers=self.headers)
+        return res.json()
+
     def refresh_token(self, old_jwt: JWT) -> JWT:
         """Refresh the token."""
         log.debug("Refreshing token")
diff --git a/dinamis_sdk/settings.py b/dinamis_sdk/settings.py
index 63c722ec40f01a14b34cfee2c966e98a7ad0cc47..be2d4a7708642274730017324e852155b325f392 100644
--- a/dinamis_sdk/settings.py
+++ b/dinamis_sdk/settings.py
@@ -8,25 +8,34 @@ from .utils import get_logger_for
 
 log = get_logger_for(__name__)
 
+# Constants
+APP_NAME = "dinamis_sdk_auth"
+MAX_URLS = 64
+S3_STORAGE_DOMAIN = "meso.umontpellier.fr"
+DEFAULT_SIGNING_ENDPOINT = (
+    "https://s3-signing-cdos.apps.okd.crocc.meso.umontpellier.fr/"
+)
+
 
 class Settings(BaseSettings):
     """Environment variables."""
 
     dinamis_sdk_ttl_margin: NonNegativeInt = 1800
     dinamis_sdk_url_duration: NonNegativeInt = 0
-    dinamis_sdk_bypass_auth_api: str = ""  # Endpoint with no authentication.
     dinamis_sdk_config_dir: str = ""
     dinamis_sdk_access_key: str = ""
     dinamis_sdk_secret_key: str = ""
     dinamis_sdk_retry_total: PositiveInt = 10
     dinamis_sdk_retry_backoff_factor: PositiveFloat = 0.8
+    dinamis_sdk_digning_disable_auth: bool = False
+    dinamis_sdk_signing_endpoint: str = DEFAULT_SIGNING_ENDPOINT
+
+    def model_post_init(self, __context):
+        """Signing endpoint validation module."""
+        if not self.dinamis_sdk_signing_endpoint.endswith("/"):
+            self.dinamis_sdk_signing_endpoint = self.dinamis_sdk_signing_endpoint + "/"
 
 
-# Constants
-APP_NAME = "dinamis_sdk_auth"
-MAX_URLS = 64
-S3_STORAGE_DOMAIN = "meso.umontpellier.fr"
-SIGNING_ENDPOINT = "https://s3-signing-cdos.apps.okd.crocc.meso.umontpellier.fr/"
 ENV = Settings()
 
 
diff --git a/tests/test_misc.py b/tests/test_misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..2adceede88e5fc62b9f91a0cff803f98df005d0d
--- /dev/null
+++ b/tests/test_misc.py
@@ -0,0 +1,11 @@
+"""Misc test module."""
+
+import dinamis_sdk
+
+
+def test_userinfo():
+    """Test userinfo method."""
+    print(dinamis_sdk.get_userinfo())
+
+
+test_userinfo()
diff --git a/tests/test_spot_6_7_drs.py b/tests/test_spot_6_7_drs.py
index 90ff1c387d7a830adc16c528e27fc37ad5e22ca4..e7568c9cb8d7abf32198d5e2d10515a4007776fe 100755
--- a/tests/test_spot_6_7_drs.py
+++ b/tests/test_spot_6_7_drs.py
@@ -1,11 +1,12 @@
 """Spot 6/7 STAC items retrieval test."""
 
-import requests
+import time
 
 import pystac_client
 
 import dinamis_sdk
 
+start = time.time()
 api = pystac_client.Client.open(
     "https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr",
     modifier=dinamis_sdk.sign_inplace,
@@ -19,5 +20,9 @@ urls = [item.assets["src_xs"].href for item in res.items()]
 print(f"{len(urls)} items found")
 assert len(urls) > 1000
 
-response = requests.get(urls[0], timeout=10)
-assert response.status_code == 200
+assert "Amz" in urls[0]
+
+print(urls[0])
+
+elapsed = time.time() - start
+print(f"Took {round(elapsed, 2)} s")