Repository: authelia/authelia

Issue:
Potential LDAP pool exhaustion
### Version


v4.39.0

### Deployment Method


Docker

### Reverse Proxy


Traefik

### Reverse Proxy Version


3.2.1

### Description


After couple of weeks authelia randomly stops responding on /api/authz/forward-auth endpoint.
Any user that tries to login using authelia receives `500 internal server error` from traefik proxy. 
I've attached debug log from Authelia it's configuration as well as docker-compose.yml.

As soon as authelia container is restarted users can login once again. 

### Reproduction


This behavior is erratic. It happened couple of times. I've enabled trace logs to gather more information

### Expectations


_No response_

### Configuration (Authelia)


```yaml
etc/authelia/configuration.yml:

server:
  address: 'tcp://:9091'

log:
  level: 'debug'

totp:
  issuer: 'example.com'

identity_validation:
  reset_password:
    jwt_secret: '__SECRET__'

ntp:
  address: 'udp://pool.ntp.example.com:123'
  version: 3
  max_desync: '3s'

session:
  # This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE
  secret: '__SECRET__'

  cookies:
    - name: 'authelia_session'
      domain: 'example.com' # Should match whatever your root protected domain is
      authelia_url: 'https://authelia.example.com'
      expiration: '1 hour'
      inactivity: '5 minutes'

  redis:
    host: '127.0.0.1'
    port: 6379
    # This secret can also be set using the env variables AUTHELIA_SESSION_REDIS_PASSWORD_FILE
    # password: authelia

regulation:
  max_retries: 3
  find_time: '2 minutes'
  ban_time: '15 minutes'

storage:
  encryption_key: 'dkmL5iqwPsom5RLVLdMCos5cd2rF4uSJqFweiTqPyNDaD5KAv5HnMpkqHYE7wFcL7'
  local:
    path: '/authelia/db.sqlite3'

# Used for adding 2FA (OTP/WebAuthn)
notifier:
  smtp:
    username: 'mailman'
    # This secret can also be set using the env variables AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
    password: '__SECRET__'
    address: 'submissions://smtp.garage.example.com:465'
    sender: 'authelia@example.com'
    # mailrise/apprise:Failed to send Telegram notification to 414546848: Bad Request: message is too long
    disable_html_emails: true

authentication_backend:
  password_reset:
    disable: false
  # How often authelia should check if there is a user update in LDAP
  refresh_interval: 1m
  ldap:
    address: 'ldaps://ldap.example.com'
    implementation: 'lldap'
    timeout: '5s'
    start_tls: false
    tls:
      skip_verify: false
      minimum_version: 'TLS1.2'
      maximum_version: 'TLS1.3'
    pooling:
      enable: true
      count: 5
      retries: 2
      timeout: '10 seconds'
    base_dn: 'DC=example,DC=com'
    user: 'uid=authelia,OU=people,DC=example,DC=com'
    password: '__SECRET__'
    additional_users_dn: 'OU=people'
    users_filter: '(&({username_attribute}={input})(objectClass=person))'
    additional_groups_dn: 'OU=groups'
    group_search_mode: 'filter'
    groups_filter: '(&(member={dn})(objectclass=groupOfUniqueNames))'
    # permit_referrals: false

password_policy:
  standard:
    enabled: true
    min_length: 64
    max_length: 0
    require_uppercase: true
    require_lowercase: true
    require_number: true
    require_special: true

webauthn:
  disable: false
  enable_passkey_login: true
  display_name: Authelia
  attestation_conveyance_preference: indirect
  selection_criteria:
    user_verification: preferred


etc/authelia/configuration.acl.yml:

###############################################################
#                   Authelia ACL                              #
###############################################################

access_control:
  networks:
    - name: 'watch.example.com'
      networks:
        - '10.5.10.20/32'
    - name: 'arr.example.com'
      networks:
        - '10.5.10.18'
  rules:
    # Disable authelia for watch.example.com
    - domain: '*.example.com'
      networks:
        - 'watch.example.com'
      policy: 'bypass'

    - domain:
        - sonarr.example.com
        - radarr.example.com
      resources:
        - '^/api([/?].*)?$'
      networks:
        - 'arr.example.com' # this probably doesn't work... see above
      policy: bypass

    - domain:
        - 'radarr.example.com'
        - 'sonarr.example.com'
        - 'nzbget.example.com'
      subject:
        - 'group:arr'
      policy: 'one_factor'

    - domain:
        - 'ara.example.com'
      subject:
        - 'group:superadmin'
      policy: 'one_factor'

    - domain:
        - 'changedetection.example.com'
      subject:
        - 'group:changedetection'
      policy: 'one_factor'

    - domain_regex: '^traefik\.\w+\.example\.com$'
      subject:
        - 'group:superadmin'
      policy: 'one_factor'

    - domain_regex: '^syncthing\.\w+\.example\.com$'
      subject:
        - 'group:superadmin'
      policy: 'one_factor'

    - domain: 'authelia.example.com'
      policy: 'one_factor'

    - domain: 'secure.example.com'
      policy: 'two_factor'


etc/authelia/oidc.yml:

identity_providers:
  oidc:
    jwks:
      - key_id: 'example'
        algorithm: 'RS256'
        use: 'sig'
        key: |
          -----BEGIN PRIVATE KEY-----
          -----END PRIVATE KEY-----
    ## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
    claims_policies:
      ## Creates the 'default' claims policy.
      default:
        id_token: ['groups', 'email', 'email_verified', 'alt_emails', 'preferred_username', 'name']
    ## See: https://www.authelia.com/c/oidc
    clients:
      - client_id: 'gitea'
        client_name: 'Gitea'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        redirect_uris:
          - 'https://gitea.example.com/user/oauth2/authelia/callback'
        scopes:
          - 'openid'
          - 'email'
          - 'profile'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_basic'
        consent_mode: implicit # disables consent requests

      - client_id: 'grafana'
        client_name: 'Grafana'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://grafana.example.com/login/generic_oauth'
        scopes:
          - 'openid'
          - 'profile'
          - 'groups'
          - 'email'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_basic'
        consent_mode: implicit # disables consent requests

      - client_id: 'harbor'
        client_name: 'Harbor'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        redirect_uris:
          - 'https://harbor.example.com/c/oidc/callback'
        grant_types:
          - 'refresh_token'
          - 'authorization_code'
        scopes:
          - 'openid'
          - 'profile'
          - 'groups'
          - 'email'
          - 'offline_access'
        userinfo_signed_response_alg: 'none'
        consent_mode: implicit # disables consent requests

      - client_id: 'headscale'
        client_name: 'headscale'
        client_secret: '__SECRET__'
        public: false
        claims_policy: 'default'
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://headscale.example.com/oidc/callback'
        scopes:
          - 'openid'
          - 'profile'
          - 'groups'
          - 'email'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_basic'
        consent_mode: implicit # disables consent requests

      - client_id: 'immich'
        client_name: 'immich'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        redirect_uris:
          - 'https://immich.example.com/auth/login'
          - 'https://immich.example.com/user-settings'
          - 'app.immich:///oauth-callback'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: "client_secret_post" # https://github.com/immich-app/immich/releases/tag/v1.132.3
        # TODO: claims STORAGE LABEL CLAIM=preferred_username, STORAGE QUOTA CLAIM=immich_quota
        consent_mode: implicit # disables consent requests

      - client_id: 'paperless'
        client_name: 'Paperless'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://paperless.example.com/accounts/oidc/authelia/login/callback/'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
          - 'groups'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_basic'
        consent_mode: implicit # disables consent requests

      - client_id: 'pbs'
        client_name: 'Proxmox Backup Server'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://pbs.example.com'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
        userinfo_signed_response_alg: 'none'
        consent_mode: implicit # disables consent requests

      - client_id: 'proxmox'
        client_name: 'Proxmox'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://proxmox.example.com'
          - 'https://t800.example.com:8006'
          - 'https://hal.example.com:8006'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
        userinfo_signed_response_alg: 'none'
        consent_mode: implicit # disables consent requests

      - client_id: 'proxmox_homelab'
        client_name: 'Proxmox Homelab'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://homelab.example.com'
          - 'https://legion.example.com:8006'
          - 'https://skynet.example.com:8006'
          - 'https://mother.example.com:8006'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
        userinfo_signed_response_alg: 'none'
        consent_mode: implicit # disables consent requests

      - client_id: 'tandoor'
        client_name: 'Tandoor'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://tandoor.example.com/accounts/oidc/authelia/login/callback/'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
          - 'groups'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_basic'
        consent_mode: implicit # disables consent requests

      - client_id: 'vikunja'
        client_name: 'Vikunja'
        client_secret: '__SECRET__'
        public: false
        authorization_policy: 'two_factor'
        redirect_uris:
          - 'https://vikunja.example.com/auth/openid/authelia'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_basic'
        consent_mode: implicit # disables consent requests



docker-compose.yml:

services:
  authelia:
    image: 'harbor.example.com/alteriks/authelia/authelia'
    container_name: 'authelia'
    volumes:
      - '/data/docker/authelia:/authelia' #db.sqlite3
      - './etc/authelia/configuration.yml:/config/configuration.yml'
      - './etc/authelia/configuration.acl.yml:/config/configuration.acl.yml'
      - './etc/authelia/oidc.yml:/config/oidc.yml'
    network_mode: host
    command:
      - 'authelia'
      - '--config=/config/configuration.yml'
      - '--config=/config/configuration.acl.yml'
      - '--config=/config/oidc.yml'
    labels:
      traefik.enable: 'true'
      traefik.http.routers.authelia.rule: 'Host(`authelia.example.com`)'
      traefik.http.routers.authelia.entrypoints: 'https'
      traefik.http.routers.authelia.tls: 'true'
      traefik.http.routers.authelia.tls.certresolver: 'le'
      traefik.http.routers.authelia.middlewares: 'hsts@docker'

      traefik.http.services.authelia.loadbalancer.server.port: 9091
    restart: 'unless-stopped'
    environment:
      TZ: 'Europe/Warsaw'
    deploy:
      restart_policy:
        condition: any
      resources:
        limits:
          memory: 300M
        reservations:
          memory: 50M

  redis:
    image: 'redis:alpine'
    container_name: 'redis'
    volumes:
      - '/data/docker/authelia/redis:/data'
    network_mode: host
    healthcheck:
      test: redis-cli ping || exit 1
    restart: 'unless-stopped'
    environment:
      TZ: 'Europe/Warsaw'
    deploy:
      resources:
        limits:
          memory: 500M
        reservations:
          memory: 50M

  traefik:
    image: 'harbor.example.com/alteriks/traefik'
    container_name: 'traefik'
    volumes:
      - /data/docker/traefik/etc/acme:/etc/acme
      - '/var/run/docker.sock:/var/run/docker.sock'
    network_mode: host
    healthcheck:
      test: ["CMD", "traefik", "healthcheck", "--entryPoints.ping.address=:8081", "--ping.entrypoint=ping", "--ping"]
    labels:
      traefik.enable: 'true'
      traefik.http.routers.api.rule: 'Host(`traefik.$HOSTNAME.example.com`)'
      traefik.http.routers.api.entrypoints: 'https'
      traefik.http.routers.api.service: 'api@internal'
      traefik.http.routers.api.tls: 'true'
      traefik.http.routers.api.tls.certresolver: 'le'
      traefik.http.routers.api.middlewares: 'authelia@docker,hsts@docker'
      traefik.http.services.traefik.loadbalancer.server.port: 8081

      traefik.http.routers.ping.service: ping@internal
      traefik.http.routers.ping.entrypoints: https
      traefik.http.routers.ping.rule: Host(`traefik.$HOSTNAME.example.com`) && PathPrefix(`/ping`)
      traefik.http.routers.ping.tls: true

      # HSTS
      traefik.http.middlewares.hsts.headers.stsSeconds: 31536000
      traefik.http.middlewares.hsts.headers.forceSTSHeader: true
      traefik.http.middlewares.hsts.headers.stsPreload: true
      traefik.http.middlewares.hsts.headers.stsIncludeSubdomains: true

      # fix: error="middleware \"authelia@docker\" does not exist", when traefik is started before authelia
      traefik.http.middlewares.authelia.forwardauth.address: 'http://127.0.0.1:9091/api/authz/forward-auth'
      traefik.http.middlewares.authelia.forwardauth.trustForwardHeader: 'true'
      traefik.http.middlewares.authelia.forwardauth.authResponseHeaders: 'Remote-User,Remote-Groups,Remote-Name,Remote-Email'

    command:
      - '--api'
      - "--ping"

      # Logging
      - '--log=true'
      - "--accesslog=false"
      - '--log.level=INFO'
      # - '--log.level=DEBUG'

      # disable BS
      - "--global.checknewversion=false"
      - "--global.sendanonymoususage=false"
      - "--api.disabledashboardad" # Disable ad in the dashboard.

      - '--providers.docker=true'
      - '--providers.docker.exposedByDefault=false'

      # Entrypoints
      - '--entrypoints.http=true'
      - '--entrypoints.http.address=:80'
      - '--entrypoints.http.http.redirections.entrypoint.to=https'
      - '--entrypoints.http.http.redirections.entrypoint.scheme=https'
      - '--entrypoints.https=true'
      - '--entrypoints.https.address=:443'
      - "--entrypoints.traefik.address=:8081" # Default :8080

      # Authelia Third Party Hosts
      # Without it other traefiks using authelia middleware will get
      # `400 Bad Request`, when requesting https://authelia.example.com/api/authz/forward-auth
      - "--entryPoints.https.forwardedHeaders.trustedIPs=10.5.10.0/24,10.5.2.0/27"
      - "--entryPoints.https.proxyProtocol.trustedIPs=10.5.10.0/24,10.5.2.0/27"

      # Lets Encrypt production
      - "--certificatesResolvers.le.acme.dnsChallenge=true"
      - "--certificatesResolvers.le.acme.dnsChallenge.provider=ovh"
      - "--certificatesResolvers.le.acme.email=alteriks@example.com"
      - "--certificatesResolvers.le.acme.storage=/etc/acme/acme_le.json"
      - "--certificatesresolvers.le.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"

      # Lets Encrypt staging
      - "--certificatesResolvers.le_staging.acme.dnsChallenge=true"
      - "--certificatesResolvers.le_staging.acme.dnsChallenge.provider=ovh"
      - "--certificatesResolvers.le_staging.acme.email=alteriks@example.com"
      - "--certificatesResolvers.le_staging.acme.storage=/etc/acme/acme_le_staging.json"
      - "--certificatesresolvers.le_staging.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"

      # HSTS
      - "traefik.http.middlewares.hsts.headers.stsSeconds=31536000"
      - "traefik.http.middlewares.hsts.headers.forceSTSHeader=true"
      - "traefik.http.middlewares.hsts.headers.stsPreload=true"
      - "traefik.http.middlewares.hsts.headers.stsIncludeSubdomains=true"

    deploy:
      restart_policy:
        condition: any
      resources:
        limits:
          memory: 300M
        reservations:
          memory: 50M
```

### Build Information


```shell
Last Tag: v4.39.0
State: tagged clean
Branch: v4.39.0
Commit: bbfa41712ce1b3e39b4798b18bd5f78e68470720
Build Number: 41111
Build OS: linux
Build Arch: amd64
Build Compiler: gc
Build Date: Sun, 16 Mar 2025 21:05:57 +1100
Extra: 

Go:
    Version: go1.24.1
    Module Path: github.com/authelia/authelia/v4
    Executable Path: github.com/authelia/authelia/v4/cmd/authelia
```

### Logs (Authelia)

See first comment

### Logs (Proxy / Application)


```shell

```

### Documentation


_No response_

### Generative AI


No

### Pre-Submission Checklist


- [x] I agree to follow the [Code of Conduct](http://www.authelia.com/code-of-conduct)

- [x] This is a bug report and not a support request

- [x] I have read the security policy and this bug report is not a security issue or security related issue

- [x] I have either included the complete configuration file or I am sure it's unrelated to the configuration

- [x] I have either included the complete debug / trace logs or the output of the build-info command if the logs are not relevant

- [x] I have provided all of the required information in full with the only alteration being reasonable sanitization in accordance with the [Troubleshooting Sanitization](https://www.authelia.com/r/sanitize) reference guide

- [x] I have checked for related proxy or application logs and included them if available

- [x] I have checked for related issues and checked the documentation


Hints from issue comments:
@alteriks: Debug log
```
time="2025-07-20T22:18:21+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:18:21+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:18:21+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:18:21+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:18:57+02:00" level=debug msg="Check authorization of subject username= groups= ip=10.5.10.20 and object https://microbin.example.com/ (method GET)."
time="2025-07-20T22:19:02+02:00" level=debug msg="Authorization Request with id '2f641bd7-0f01-4e91-be47-f483bb8b407e' on client with id 'grafana' is being processed" method=GET path=/api/oidc/authorization remote_ip=10.5.10.20
time="2025-07-20T22:19:10+02:00" level=debug msg="Authorization Request with id 'bfe7f8c9-0226-492d-9fe1-bc87fdb2b7ce' on client with id 'proxmox' is being processed" method=GET path=/api/oidc/authorization remote_ip=10.5.2.3
time="2025-07-20T22:19:11+02:00" level=debug msg="Authorization Request with id 'bfe7f8c9-0226-492d-9fe1-bc87fdb2b7ce' on client with id 'proxmox' is not being redirected for reauthentication" authenticated_at="2025-07-07 12:32:35 +0000 UTC" method=GET path=/api/oidc/authorization prompt= remote_ip=10.5.2.3 requested_at="2025-07-20 20:19:10.984734036 +0000 UTC"
time="2025-07-20T22:19:11+02:00" level=debug msg="Authorization Request with id 'bfe7f8c9-0226-492d-9fe1-bc87fdb2b7ce' on client with id 'proxmox' was successfully processed, proceeding to build Authorization Response" method=GET path=/api/oidc/authorization remote_ip=10.5.2.3
time="2025-07-20T22:19:12+02:00" level=debug msg="Access Request with id 'bfe7f8c9-0226-492d-9fe1-bc87fdb2b7ce' on client with id 'proxmox' is being processed" method=POST path=/api/oidc/token remote_ip=10.5.2.15
time="2025-07-20T22:19:12+02:00" level=debug msg="Access Request with id 'bfe7f8c9-0226-492d-9fe1-bc87fdb2b7ce' on client with id 'proxmox' has successfully been processed" method=POST path=/api/oidc/token remote_ip=10.5.2.15
time="2025-07-20T22:19:12+02:00" level=debug msg="User Info Request with id '002a5dc5-8015-4517-9bef-bb04d0d8b6ce' is being processed" method=GET path=/api/oidc/userinfo remote_ip=10.5.2.15
time="2025-07-20T22:19:12+02:00" level=debug msg="User Info Request with id '002a5dc5-8015-4517-9bef-bb04d0d8b6ce' on client with id 'proxmox' is being returned unsigned as per the registered client configuration" method=GET path=/api/oidc/userinfo remote_ip=10.5.2.15
time="2025-07-20T22:19:12+02:00" level=debug msg="User Info Request with id '002a5dc5-8015-4517-9bef-bb04d0d8b6ce' on client with id 'proxmox' was successfully processed" method=GET path=/api/oidc/userinfo remote_ip=10.5.2.15
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/error (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/status (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/error (method GET)."
time="2025-07-20T22:19:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/status (method GET)."
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:33+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:19:33+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:19:33+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:37+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:43+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:19:43+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/error (method GET)."
time="2025-07-20T22:19:43+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:50+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/status (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/status (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/error (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:19:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/assets/img/favicon-notify.png (method GET)."
time="2025-07-20T22:19:57+02:00" level=debug msg="Check authorization of subject username= groups= ip=10.5.10.20 and object https://microbin.example.com/ (method GET)."
time="2025-07-20T22:20:02+02:00" level=debug msg="Authorization Request with id '8c3c6411-1340-4f94-9fd9-dc432b4e238a' on client with id 'grafana' is being processed" method=GET path=/api/oidc/authorization remote_ip=10.5.10.20
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/error (method GET)."
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/status (method GET)."
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:20:03+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:20:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:20:03+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:03+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:03+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:09+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/error (method GET)."
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:22+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:23+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:20:23+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/status (method GET)."
time="2025-07-20T22:20:23+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:33+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:20:33+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/status (method GET)."
time="2025-07-20T22:20:41+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:43+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:20:43+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/discovery (method GET)."
time="2025-07-20T22:20:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:53+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:20:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/assets/img/favicon-notify.png (method GET)."
time="2025-07-20T22:20:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:53+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:20:57+02:00" level=debug msg="Check authorization of subject username= groups= ip=10.5.10.20 and object https://microbin.example.com/ (method GET)."
time="2025-07-20T22:21:02+02:00" level=debug msg="Authorization Request with id '0295da8e-d38e-4af2-901e-e432dbd51f8e' on client with id 'grafana' is being processed" method=GET path=/api/oidc/authorization remote_ip=10.5.10.20
time="2025-07-20T22:21:03+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:21:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:21:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/events?since=50441 (method GET)."
time="2025-07-20T22:21:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/connections (method GET)."
time="2025-07-20T22:21:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/error (method GET)."
time="2025-07-20T22:21:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/status (method GET)."
time="2025-07-20T22:21:03+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/events?since=6971 (method GET)."
time="2025-07-20T22:21:13+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:21:13+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:21:13+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/status (method GET)."
time="2025-07-20T22:21:23+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:21:23+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.nfs.example.com/rest/system/error (method GET)."
time="2025-07-20T22:21:24+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:21:33+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:21:33+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/status (method GET)."
time="2025-07-20T22:21:43+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:21:43+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/error (method GET)."
time="2025-07-20T22:21:45+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
time="2025-07-20T22:21:53+02:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:529 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:163       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:60        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func31\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.59.0/server.go:2380                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.59.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=alteriks@example.com
time="2025-07-20T22:21:53+02:00" level=debug msg="Check authorization of subject username=alteriks@example.com groups=arr,changedetection,grafana_admin,harbor_admin,headscale_user,superadmin ip=10.5.2.3 and object https://syncthing.moar.example.com/rest/system/error (method GET)."
time="2025-07-20T22:21:54+02:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=10.5.2.3 username=alteriks@example.com
```@james-d-elliott: What makes you think it stops responding? What do the proxy debug logs show? Do you happen to know what's wrong with your LDAP server?@alteriks: From what have I gathered Authelia stops responding on /api/authz/forward-auth endpoint and traefik severs this connection after timeout. From user authelia webUI works just fine until one clicks 'sign-in'.

I've got secondary authelia instance which is connected to the same lldap instance. Which works fine - users can still authorize. Unfortunately I've never got enough time to finish HA in my homelab. Currently it is setup like this:
- 2 VMs with authelia,traefik,keepalived
- 2 VMs with lldap,traefik,keepalived

Keepalived manages floating IP between both authelia cluster and lldap cluster. 
As soon as problematic authelia instance is stopped, keepalived moves floating IP to secondary instance and everything works with same lldap instance. Unfortunately secondary authelia also uses sqlite database, so they aren't in sync. Also stopping authelia is manual process. 
It's manual because docker/keepalived checks only default health endpoint:
- http://127.0.0.1:9091/api/health
And problematic authelia instance returns its status as healthy.

Right now restarting dubious authelia is the fastest way to get AAA operating. @james-d-elliott: Does it come good as soon as it's restarted?@alteriks: Yes. Restarting immediately solves problem on primary authelia instance.@james-d-elliott: Think it must be the pooling then, will take a look if anything jumps out at me otherwise may need you to run it in trace until it happens (potentially after adding more trace logs).@alteriks: Here's what I've done today so it will be easier to find culprit when next authelia+lldap hiccup will happen. 

- Bumped authelia to newest version 4.39.5, enable trace logs
- Bumped  to newest version 4.39.5, enable access logs
- Enabled LLDAP_VERBOSE=true on lldap
- redeployed traefik and authelia stack on auth0X VMs  using ansible

I've tried to decode sniffed TLS traffic between Authelia and LDAP, but it seems that neither supports the SSLKEYLOGFILE environment variable. I've never deployed any MITM proxy and I don't know if it's worth the hassle.

My plan for next authelia hiccup:
1) gather authelia logs
2) ~~sniff network traffic between authelia and lldap~~
3) restart primary traefik instance and try to login again
4) stop primary lldap instance and wait at least 1m (authentication_backend.refresh_interval) so authelia can connect to secondary lldap instance

If you'd like to share any pointers regarding what should I do in order to capture more data I'd be happy to help. Unfortunately this problem happens sporadically and I don't know how to trigger it.@alteriks: Another occurrence took place after less than 24h

1) Trace log is in following attachment [authelia_trace.log](https://github.com/user-attachments/files/21365000/authelia_trace.log)
Unfortunately it's not full log. I didn't redirect logging before I realized that it's being truncated. As far as I can tell I didn't noticed other messages that are already in attached file.
 
3) Restarting traefik didn't help
4) I didn't restart primary ldap instance. But I've tried killing TCP Established connections with `ss`  
It seems that authelia during problematic state cannot recreate pool connections after they're terminated.
<img width="1256" height="522" alt="Image" src="https://github.com/user-attachments/assets/a78f2788-da22-4333-ab90-e9129670fea8" />

I've tried the same on secondary authelia:
```bash
sudo ss -K dst 10.5.10.40 dport = 636

i=0 
while true; do 
  let "i=i+1"; 
  sleep 1; 
  echo $i; 
  sudo ss |grep 10.5.10.40; 
done
```
Output:
```
Netid        State        Recv-Q        Send-Q                 Local Address:Port                  Peer Address:Port         
tcp          ESTAB        0             0                         10.5.10.45:46282                   10.5.10.40:ldaps        
tcp          ESTAB        0             0                         10.5.10.45:46286                   10.5.10.40:ldaps        
tcp          ESTAB        0             0                         10.5.10.45:46294                   10.5.10.40:ldaps        
tcp          ESTAB        0             0                         10.5.10.45:46318                   10.5.10.40:ldaps        
tcp          ESTAB        0             0                         10.5.10.45:46308                   10.5.10.40:ldaps   
1
2
3
4
5

[...]

531
532
533
534
tcp   ESTAB 0      0                                                                              10.5.10.45:34980            10.5.10.40:ldaps  
tcp   ESTAB 0      0                                                                              10.5.10.45:34968            10.5.10.40:ldaps  
535
tcp   ESTAB 0      0                                                                              10.5.10.45:34980            10.5.10.40:ldaps  
tcp   ESTAB 0      0                                                                              10.5.10.45:34968            10.5.10.40:ldaps  
536
```

Healthy authelia didn't reestablished pool by itself. After 534 seconds I've tried logging in using this instance and authelia established pool to lldap.@james-d-elliott: The pool will not create another connection until the ldap driver reports the connection is closed, closing, or in error. In the instance where all connections are being used this is the case, but it'll wait for 10 seconds per your config for an existing connection to return to the pool (context deadline exceeded).

> After 534 seconds I've tried logging in using this instance and authelia established pool to lldap.

Are you saying it recovered after 10 mins?@alteriks: Sorry for being unclear. No it did not recover `while true` test was done on healthy instance. 

I haven't seen pool being reestablished on unhealthy instance (attached image). I've waited couple minutes and restarted it.@james-d-elliott: The user who requested this tested it for [multiple weeks](https://github.com/authelia/authelia/discussions/7192#discussioncomment-9722537). So it's very strange overall. The killed sockets are not entirely an unexpected outcome as abrupt closes like this often are poorly communicated.

Think the only thing left is for me to make a build with some extra logging. I'll let you know when that's ready.@thielj: @james-d-elliott Actually, the user who tested this for multiple weeks is here as well now :(

I had this running for almost a year with your feature build and a patched LLDAP version created about the same time.

Now that I have upgraded to the latest Authelia (4.39.6) and LLDAP I'm seeing the same errors, i.e.  "context deadline exceeded" and LDAP timeouts. It might be LLDAP - still investigating.
@alteriks: @james-d-elliott I've been running authelia instance for over 20 without ldap pool, and haven't seen "context deadline exceeded" error again. I haven't touched authelia config(besides disabling pool) or version.
The only thing that has changed is lldap version. I've updated lldap to `0.6.2` 3 days ago. @james-d-elliott: Can we run the `debug-ldap-pool` branch (tagged as such, or I can link to the builds if needed) with log level trace? It should record a lot of logs related to pool lifecycle. As far as what it can be the only potential thing that occurs to me right now is something to do with the library and handling of connections closed upstream.@alteriks: @james-d-elliott I've had troubles building container with `cmd/dev/authelia-scripts docker build`, but I've managed to build authelia binary and copy it directly to `/app/authelia`. I've set `authentication_backend.ldap.pooling.enable` to `true`:
```bash
 git diff etc/authelia/configuration.yml
diff --git a/etc/authelia/configuration.yml b/etc/authelia/configuration.yml
index 9bc85a1..6d1de5b 100644
--- a/etc/authelia/configuration.yml
+++ b/etc/authelia/configuration.yml
@@ -99,7 +99,7 @@ authentication_backend:
       minimum_version: 'TLS1.2'
       maximum_version: 'TLS1.3'
     pooling:
-      enable: false
+      enable: true
       count: 5
       retries: 2
       timeout: '10 seconds'
```

After container restart I've got:

```bash
time="2025-09-01T14:00:44+02:00" level=info msg="Authelia untagged-v4.39.7-dirty (debug-ldap-pool, 563fd12) is starting" caller="github.com/spf13/cobra@v1.9.1/command.go:1015 (*Command).execute"
time="2025-09-01T14:00:44+02:00" level=info msg="Log severity set to trace" caller="github.com/authelia/authelia/v4/internal/logging/logger.go:102 setLevelStr"
```

But I didn't notice any new trace log messages ie `"Creating new pooled client"` is this ok, or am I missing something? @thielj: @james-d-elliott It does seem to be related to connections closed from the LDAP server side (or haproxy in-between). Is there a container image for debug-ldap-pool? I think I can replicate this.@james-d-elliott: Yes, the `debug-ldap-pool` tag.@thielj: @james-d-elliott I don't have much for you, bu maybe this helps.

When I kill the sessions in haproxy, Authelia detects this and reconnects:

```
authelia  | time="2025-09-23T15:19:54Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=6 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:19:54Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:19:55Z" level=trace msg="New pooled client created" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:193 (*PooledLDAPClientFactory).new" client=7 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:19:55Z" level=trace msg="New client acquired" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:269 (*PooledLDAPClientFactory).acquire" client=7 provider="pooled ldap factory"
```

When I kill the session, but DRAIN all available servers, this happens:

```
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=12 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Error acquiring new client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:262 (*PooledLDAPClientFactory).acquire" error="error occurred establishing new client for the pool: error occurred performing bind: unable to read LDAP response packet: EOF" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=11 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Error acquiring new client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:262 (*PooledLDAPClientFactory).acquire" error="error occurred establishing new client for the pool: error occurred performing bind: unable to read LDAP response packet: EOF" provider="pooled ldap factory"
```

After the above, we're just seeing the usual errors. So my interpretation is that those not-connected clients fill the pool, are never released and can't be replaced when a healthy server comes back. 

```
  refresh_interval: always
  ldap:
    address: 'ldap://[REDACTED]'
    timeout: '5s'
    pooling:
      enable: true
      count: 2
      retries: 2
      timeout: '2s'
    implementation: lldap
```

Is responding with 401 to upstream errors "by design"?@james-d-elliott: Both of those logs are expected outcomes.

What do you mean responding to upstream errors?@thielj: A connection pool filled with sticky unusable connections that can't be replaced without a restart of Authelia is the expected outcome? 

Upstream errors, like an LDAP or DB server temporarily unavailable, result in a 401 status, where 500, 503 or 504 might be more appropriate and easier detectable.

```
authelia  | time="2025-09-23T14:43:06Z" level=debug msg="Error occurred while attempting to authenticate a request but the matched rule was a bypass rule" caller="github.com/authelia/authelia/v4/internal/handlers/handler_authz.go:90 (*Authz).Handler" error="unable to retrieve details for user '[REDACTED]': context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=[REDACTED]
authelia  | time="2025-09-23T14:43:06Z" level=debug msg="Responding 401 WWW-Authenticate" caller="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:365 (*HeaderAuthnStrategy).HandleUnauthorized" method=GET path=/api/authz/forward-auth remote_ip=[REDACTED]
authelia  | time="2025-09-23T14:43:06Z" level=trace msg="Replied (status=401)" caller="github.com/authelia/authelia/v4/internal/middlewares/log_request.go:16 handlerMain.LogRequest.func30" method=GET path=/api/authz/forward-auth remote_ip=[REDACTED]
``` @james-d-elliott: Entirely expected and intentionally designed to have that status code when there is a fault with the LDAP server connection. We shouldn't leak information about why the authentication may have failed to a potential malicious user. It can allow them to use attack side channels. 

> A connection pool filled with sticky unusable connections that can't be replaced without a restart of Authelia is the expected outcome?

Might pay to show the logs regarding this.@thielj: As mentioned previously, I get these:

```
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=12 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Error acquiring new client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:262 (*PooledLDAPClientFactory).acquire" error="error occurred establishing new client for the pool: error occurred performing bind: unable to read LDAP response packet: EOF" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=11 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Error acquiring new client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:262 (*PooledLDAPClientFactory).acquire" error="error occurred establishing new client for the pool: error occurred performing bind: unable to read LDAP response packet: EOF" provider="pooled ldap factory"
```

And after that, all LDAP lookups fail with the usual `msg="Error occurred while attempting to update user details for user" error="context deadline exceeded"`.

Here's the additional log output from Authelia (intentionally left blank, as there is no log):

```
```

And here's the log from HAProxy showing that no further connections are opened (intentionally left blank as there is no log):

```
```

Might pay to add some lines logging this ;)
@thielj: From the view of a no-Go programmer - the underlying issue is in acquire:

```go
case client = <-f.pool:
```

This pops connections out of the pool until it's empty. Then it blocks until the dreaded "context deadline exceeded" error ends the misery.

The code below it doesn't replenish connections if they can't be created:

```go
if client, err = f.new(); err != nil {
    time.Sleep(f.sleep)

    continue
}
```

So the loop completely drains the pool. For a count of 2, this resulted in:

```
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=12 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:00Z" level=trace msg="Error acquiring new client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:262 (*PooledLDAPClientFactory).acquire" error="error occurred establishing new client for the pool: error occurred performing bind: unable to read LDAP response packet: EOF" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Client is closing or invalid" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:259 (*PooledLDAPClientFactory).acquire" client=11 provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Creating new pooled client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:183 (*PooledLDAPClientFactory).new" provider="pooled ldap factory"
authelia  | time="2025-09-23T15:26:01Z" level=trace msg="Error acquiring new client" caller="github.com/authelia/authelia/v4/internal/authentication/ldap_client_factory.go:262 (*PooledLDAPClientFactory).acquire" error="error occurred establishing new client for the pool: error occurred performing bind: unable to read LDAP response packet: EOF" provider="pooled ldap factory"
```

Further calls to acquire start with an empty pool,block immediately and result in the usual context deadline errors.

I think the original idea was to heal/refill the pool above the loop:

```go
if cap(f.pool) != f.config.Pooling.Count {
```

I think this should be `len(f.pool)`, as capacity of the channel and the config value are constant.

Then `Initialize()` needs a slight change to refill the pool even if it has already been created. Something like this:

```go
func (f *PooledLDAPClientFactory) Initialize() error {
	f.mu.Lock()

	defer f.mu.Unlock()

	if f.pool == nil {
		f.pool = make(chan *LDAPClientPooled, f.config.Pooling.Count)
	}

	var errs []error
	startLen := len(f.pool)
	for i := startLen; i < f.config.Pooling.Count; i++ {
		if client, err = f.new(); err != nil {
			errs = append(errs, err)

			continue
		}

		f.pool <- client
	}

	if len(f.pool) < f.config.Pooling.Count {
		return fmt.Errorf("pool not filled after %d attempts: %v", f.config.Pooling.Count, errs)
	}

	return nil
}
```

Finally, `ReleaseClient()` might benefit from not adding invalid connections back to the pool:

```go
func (f *PooledLDAPClientFactory) ReleaseClient(client ldap.Client) error {
	f.mu.Lock()

	defer f.mu.Unlock()

	if f.closing {
		return client.Close()
	}

	// Only pooled and valid clients get added back to the pool
	if pool, ok := client.(*LDAPClientPooled); !ok || pool == nil || pool.IsClosing() || pool.Client == nil || len(f.pool) >= cap(f.pool) {
		return client.Close()
	} else {
		f.pool <- pool
	}

	return nil
}
```

Apologies for the long line...@james-d-elliott: `Creating new pooled client` is logged when a new connection is opened. This indicates that the connection is probably never established with the server i.e. Authelia tries to connect but can't. Are you restoring the access to the server when those logs are being generated? If not then that's completely normal.@thielj: The error is in the code.See my previous comment.



On Tue, Sep 23, 2025, 23:27 James Elliott ***@***.***> wrote:

> *james-d-elliott* left a comment (authelia/authelia#9936)
> <https://github.com/authelia/authelia/issues/9936#issuecomment-3325743028>
>
> Creating new pooled client is logged when a new connection is opened.
> This indicates that the connection is probably never established with the
> server i.e. Authelia tries to connect but can't. Are you restoring the
> access to the server when those logs are being generated? If not then
> that's completely normal.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/authelia/authelia/issues/9936#issuecomment-3325743028>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AA6CUVOIGO67DJ5VJWP444T3UHCLZAVCNFSM6AAAAACB6KYZJOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGMRVG42DGMBSHA>
> .
> You are receiving this because you commented.Message ID:
> ***@***.***>
>
@james-d-elliott: Your assessment is not correct in my opinion. The replenishment of the pool occurs after the client is released. It should *absolutely not* be returned to the pool before this time as it will absolutely introduce a data race.

We need to know the answer to the question. If the answer is no, we'll need new logs with the corruption of the pool occurring, and then the restoration of the TCP access to the LDAP server.@thielj: Look at your code. LDAP Server goes down and new connections can't be established. What happens here?

```go
case client = <-f.pool:
  if client.IsClosing() || client.Client == nil {
    for {
    	select {
    	case <-ctx.Done():
    		return nil, ctx.Err()
    	default:
    		if client, err = f.new(); err != nil {
    			time.Sleep(f.sleep)
    
    			continue
    		}
    		return client, nil
    	}
    }
```

It drains the pool until it is empty, failing to create new connections.

LDAP server comes up again. Does that change something?

Look at your code again. What happens here when the pool is empty?

```go
case client = <-f.pool:
```

Nothing, until the timeout hits.

See my full, edited comment with the suggested fixes here: https://github.com/authelia/authelia/issues/9936#issuecomment-3325540548@james-d-elliott: I can reopen this if we get the required information. @thielj: No worries, I will fork and fix it myself tomorrow.@james-d-elliott: I appreciate the enthusiasm but the instructions remain unchanged and it's not appropriate to instruct users to use unverified binaries outside of the authelia official channels, please don't do this again.

Please use the provided container (authelia/authelia:debug-ldap-pool) to provide the trace logs (see the scenario description below). Two separate people have made two separate attempts to replicate the issue on separate architectures similar in design to the ones described with the reproduction instructions without success.

Currently the logs are showing a new connection being made and that connection resulting in an EOF, the question at this stage is what do the logs look like before / after restoration of the LB. Also of (admittedly lesser) importance is if this can be properly replicated in a supported architecture (i.e. if you're using lldap a direct connection to a single instance). @thielj: Fair enough. The source code is in the ldap-pool-9936 branch over here:

https://github.com/thielj/authelia/blob/ldap-pool-9936/internal/authentication/ldap_client_factory.go

It implements a thread-safe non-locking client pool that maintains half of the pool size as minimum and the configured `count` as a maximum. This can obviously be changed. The docs regarding the `count` parameter are a bit ambiguous and I followed your lead and kept the pool channel capacity at `count`.

The current Dockerfile.dev has some issues with building the frontend but they are easy to fix. This worked for me:

```
RUN \
	apk add --no-cache git && \
	yarn global add pnpm && \
	HUSKY=0 NPM_CONFIG_IGNORE_SCRIPTS=true pnpm install --frozen-lockfile && \
	pnpm coverage
```

I'm running this on one server now. It would obviously benefit from more testing. I can turn it into a PR after some cleanup.

Contrary to what many people may think, the biggest advantage of pooling is the connection re-use, avoiding the costly (argon2) hash on every new connection. Even with a pool size of one, people would see many LDAP operations drop from 300ms+ to 1ms (with binds as user being the obvious exemption).@james-d-elliott: Did you write all this yourself? I'm apprehensive about your current redesign but don't want to be disrespectful to your efforts either. The introduction of a new complex package and especially the `sync/atomic` package in something already rather complicated is probably not be the answer. The `sync/atomic` package generally should be reserved for cases where locks are not suitable. They only guarantee safety against data races and threading issues, not the order in which everything will take place. It's very common when using them in this way to fall victim to go routine deadlocks.

Might be worth us focusing on diagnosing the issue here rather than proposed fixes which also effectively include a significant feature change, I'd welcome a separate [Discussion](https://github.com/authelia/authelia/discussions).

If anyone wishes to engage in the diagnostic process I'm happy to reopen the issue i.e. @thielj @alteriks @pedorich-n @jgable01 using the trace logs from the `authelia/authelia:debug-ldap-pool` (it'd be great to get logs before the issue occurs, and after the issue with the LDAP server is resolved).

> Contrary to what many people may think, the biggest advantage of pooling is the connection re-use, avoiding the costly (argon2) hash on every new connection. Even with a pool size of one, people would see many LDAP operations drop from 300ms+ to 1ms (with binds as user being the obvious exemption).

This is precisely why my initial direction when you asked about caching was to do this, as well as the fact the LDAP client implementation is entirely not go routine safe from memory.@thielj: I think you still haven't understood what the original author clearly stated and I have confirmed "It seems that authelia during problematic state cannot recreate pool connections after they're terminated".

There simply is no further related log output, including from your debug build. 

Anyway, I don't really fancy starting a discussion about the problems of mutexes. 

I think you will find that LDAP clients are not safe to be *USED* concurrently, very much like most HTTP clients either. That isn't the same as passing them between threads/goroutines.

I've provided a PR here: https://github.com/authelia/authelia/pull/10392

Happy to explain, clarify or review details - but absolutely no fan of bike shedding.

@james-d-elliott: > There simply is no further related log output, including from your debug build.

So after the issue occurs no logs are printed with trace log level? Even from the request logging?@james-d-elliott: We've reproduced this and have a fix.@james-d-elliott: @pedorich-n since you reacted would you be interested in testing this for us in your situation by chance?@pedorich-n: I've experienced this (or a similar) issue before. I remember seeing `error="context deadline exceeded"`, that's is how I found this thread. Disabling LDAP pooling seemed to resolve it for me.

I'm currently away from my PC for a while, so I can’t test the fix right now, sorry. If testing is still needed in a couple of weeks, I’ll try to reproduce the behavior then.@Crowley723: > I'm currently away from my PC for a while, so I can’t test the fix right now, sorry. If testing is still needed in a couple of weeks, I’ll try to reproduce the behavior then.

The goal here is to identify and fix the stated issue any any that might be related. We already found and fixed two other issues related to the main one.
Whenever you get time, testing the fix would be really helpful. 

@james-d-elliott: Thats fine we can move ahead with the assumption that this solves the issue. The other two unrelated issues are also solved this third one replicates the condition after the issue occuring almost exactly so there are effectively 3 issues in this area that are better; and one is almost certainly the issue  described 

I just have to add some tests to determine whether or not I can prove the failure with a test and prove the fix with a test which I'm fairly certain I can.@pedorich-n: Hello! I am back, and I did some testing. 

I can reliably cause this issue on my machine with `v4.39.12`. I can post a longer guide if you want, but TL;DR is that I have [Netdata](https://www.netdata.cloud/) service secure via authz ForwardAuth with Traefik as a proxy, and if I leave the Netdata page open for ~5 minutes (which constantly fetches new data to display), I start seeing the following in the logs:
```
authelia[58369]: time="2025-10-23T19:38:43+09:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=192.168.10.10 username=XXXX
authelia[58369]: time="2025-10-23T19:38:43+09:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=192.168.10.10 username=XXXX
authelia[58369]: time="2025-10-23T19:38:44+09:00" level=debug msg="Checking the authentication backend for an updated profile for user" method=GET path=/api/authz/forward-auth remote_ip=192.168.10.10 username=XXXX
authelia[58369]: time="2025-10-23T19:38:53+09:00" level=error msg="Error occurred while attempting to update user details for user" error="context deadline exceeded" method=GET path=/api/authz/forward-auth remote_ip=192.168.10.10 stack="github.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:530 handleSessionValidateRefresh\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:477 handleAuthnCookieValidate\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz_authn.go:117 (*CookieSessionAuthnStrategy).Get\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:162       (*Authz).authn\ngithub.com/authelia/authelia/v4/internal/handlers/handler_authz.go:59        (*Authz).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/bridge.go:66            handlerMain.(*BridgeBuilder).Build.func1.1\ngithub.com/authelia/authelia/v4/internal/middlewares/headers.go:30           SecurityHeadersBase.func1\ngithub.com/fasthttp/router@v1.5.4/router.go:441                              (*Router).Handler\ngithub.com/authelia/authelia/v4/internal/middlewares/log_request.go:14       handlerMain.LogRequest.func30\ngithub.com/authelia/authelia/v4/internal/middlewares/errors.go:38            RecoverPanic.func1\ngithub.com/valyala/fasthttp@v1.67.0/server.go:2465                           (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.67.0/workerpool.go:225                        (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.67.0/workerpool.go:197                        (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                                     goexit" username=XXX
```

With the build from the PR, I see occasional errors like this:
```
authelia[69696]: time="2025-10-23T19:45:35+09:00" level=error msg="Request timeout occurred while handling request from client." error="read tcp 127.0.0.1:9091->127.0.0.1:38420: i/o timeout" method=GET path=/ remote_ip=127.0.0.1 stack="github.com/authelia/authelia/v4/internal/server/handlers.go:91 New.handleError.func2\ngithub.com/valyala/fasthttp@v1.67.0/server.go:2967             (*Server).writeErrorResponse\ngithub.com/valyala/fasthttp@v1.67.0/server.go:2394             (*Server).serveConn\ngithub.com/valyala/fasthttp@v1.67.0/workerpool.go:225          (*workerPool).workerFunc\ngithub.com/valyala/fasthttp@v1.67.0/workerpool.go:197          (*workerPool).getCh.func1\nruntime/asm_amd64.s:1700                                       goexit" status_code=408
```
But at least Authelia continues functioning. 

Worth noting: I am running an unofficial build because I use NixOS. But it doesn't apply any extra patches: https://github.com/NixOS/nixpkgs/blob/5a0711127cd8b916c3d3128f473388c8c79df0da/pkgs/servers/authelia/default.nix

Let me know if you need more info!@james-d-elliott: Thanks @pedorich-n for your helpful response, and your general cooperation. 

We found similar in our testing but it's reassuring to know we can replicate it.

I'll look to merge and release this soon.@james-d-elliott: @all-contributors please add @pedorich-n for userTesting@allcontributors: @james-d-elliott 

I've put up [a pull request](https://github.com/authelia/authelia/pull/10605) to add @pedorich-n! :tada:@pedorich-n: Glad I could help. 
Thanks!

Solution patch:
diff --git a/internal/authentication/gen.go b/internal/authentication/gen.go
index 279af7aec..33919605a 100644
--- a/internal/authentication/gen.go
+++ b/internal/authentication/gen.go
@@ -3,7 +3,7 @@ package authentication
 // This file is used to generate mocks. You can generate all mocks using the
 // command `go generate github.com/authelia/authelia/v4/internal/authentication`.
 
-//go:generate mockgen -package authentication -destination ldap_client_mock_test.go -mock_names Client=MockLDAPClient github.com/go-ldap/ldap/v3 Client
+//go:generate mockgen -package authentication -destination ldap_client_mock_test.go -mock_names LDAPClient=MockLDAPClient github.com/authelia/authelia/v4/internal/authentication LDAPClient
 //go:generate mockgen -package authentication -destination ldap_client_dialer_mock_test.go -mock_names LDAPClientDialer=MockLDAPClientDialer github.com/authelia/authelia/v4/internal/authentication LDAPClientDialer
 //go:generate mockgen -package authentication -destination ldap_client_factory_mock_test.go -mock_names LDAPClientFactory=MockLDAPClientFactory github.com/authelia/authelia/v4/internal/authentication LDAPClientFactory
 //go:generate mockgen -package authentication -destination file_user_provider_database_mock_test.go -mock_names FileUserProviderDatabase=MockFileUserDatabase github.com/authelia/authelia/v4/internal/authentication FileUserProviderDatabase
diff --git a/internal/authentication/ldap_client_dialer.go b/internal/authentication/ldap_client_dialer.go
index 4577e2eae..7e298f46d 100644
--- a/internal/authentication/ldap_client_dialer.go
+++ b/internal/authentication/ldap_client_dialer.go
@@ -6,10 +6,10 @@ import (
 	"github.com/go-ldap/ldap/v3"
 )
 
-// LDAPClientDialer is an abstract type that dials a ldap.Client.
+// LDAPClientDialer is an abstract type that dials a LDAPClient.
 type LDAPClientDialer interface {
-	// DialURL takes a single address and dials it returning the ldap.Client.
-	DialURL(addr string, opts ...ldap.DialOpt) (client ldap.Client, err error)
+	// DialURL takes a single address and dials it returning the LDAPClient.
+	DialURL(addr string, opts ...ldap.DialOpt) (client LDAPClient, err error)
 }
 
 // NewLDAPClientDialerStandard returns a new *LDAPClientDialerStandard.
@@ -17,12 +17,12 @@ func NewLDAPClientDialerStandard() *LDAPClientDialerStandard {
 	return &LDAPClientDialerStandard{}
 }
 
-// LDAPClientDialerStandard is a concrete type that dials a ldap.Client and returns it, implementing the
+// LDAPClientDialerStandard is a concrete type that dials a LDAPClient and returns it, implementing the
 // LDAPClientDialer.
 type LDAPClientDialerStandard struct{}
 
-// DialURL takes a single address and dials it returning the ldap.Client.
-func (d *LDAPClientDialerStandard) DialURL(addr string, opts ...ldap.DialOpt) (client ldap.Client, err error) {
+// DialURL takes a single address and dials it returning the LDAPClient.
+func (d *LDAPClientDialerStandard) DialURL(addr string, opts ...ldap.DialOpt) (client LDAPClient, err error) {
 	if client, err = ldap.DialURL(addr, opts...); err != nil {
 		return nil, fmt.Errorf("failed to dial LDAP server at %s: %w", addr, err)
 	}
diff --git a/internal/authentication/ldap_client_factory.go b/internal/authentication/ldap_client_factory.go
index 58c7db4ba..d1c244264 100644
--- a/internal/authentication/ldap_client_factory.go
+++ b/internal/authentication/ldap_client_factory.go
@@ -21,8 +21,8 @@ import (
 // LDAPClientFactory an interface describing factories that produce LDAPConnection implementations.
 type LDAPClientFactory interface {
 	Initialize() (err error)
-	GetClient(opts ...LDAPClientFactoryOption) (client ldap.Client, err error)
-	ReleaseClient(client ldap.Client) (err error)
+	GetClient(opts ...LDAPClientFactoryOption) (client LDAPClient, err error)
+	ReleaseClient(client LDAPClient) (err error)
 	Close() (err error)
 }
 
@@ -59,11 +59,11 @@ func (f *StandardLDAPClientFactory) Initialize() (err error) {
 	return nil
 }
 
-func (f *StandardLDAPClientFactory) GetClient(opts ...LDAPClientFactoryOption) (client ldap.Client, err error) {
-	return getLDAPClient(f.config.Address.String(), f.config.User, f.config.Password, f.config.Timeout, f.dialer, f.tls, f.config.StartTLS, f.opts, opts...)
+func (f *StandardLDAPClientFactory) GetClient(opts ...LDAPClientFactoryOption) (client LDAPClient, err error) {
+	return ldapDialBind(f.config.Address.String(), f.config.User, f.config.Password, f.config.Timeout, f.dialer, f.tls, f.config.StartTLS, f.opts, opts...)
 }
 
-func (f *StandardLDAPClientFactory) ReleaseClient(client ldap.Client) (err error) {
+func (f *StandardLDAPClientFactory) ReleaseClient(client LDAPClient) (err error) {
 	if err = client.Close(); err != nil {
 		return fmt.Errorf("error occurred closing LDAP client: %w", err)
 	}
@@ -122,36 +122,33 @@ type PooledLDAPClientFactory struct {
 	opts   []ldap.DialOpt
 	dialer LDAPClientDialer
 
-	pool chan *LDAPClientPooled
-	mu   sync.Mutex
+	pool chan *PooledLDAPClient
 
 	sleep time.Duration
 
-	next int
-
+	mu      sync.Mutex
+	next    int
 	closing bool
 }
 
 func (f *PooledLDAPClientFactory) Initialize() (err error) {
-	f.mu.Lock()
-
-	defer f.mu.Unlock()
-
 	if f.pool != nil {
 		return nil
 	}
 
-	f.pool = make(chan *LDAPClientPooled, f.config.Pooling.Count)
+	f.pool = make(chan *PooledLDAPClient, f.config.Pooling.Count)
 
 	var (
 		errs   []error
-		client *LDAPClientPooled
+		client *PooledLDAPClient
 	)
 
 	for i := 0; i < f.config.Pooling.Count; i++ {
-		if client, err = f.new(); err != nil {
+		if client, err = f.dial(); err != nil {
 			errs = append(errs, err)
 
+			f.log.WithError(err).Debug("Error occurred dialing a pooled client")
+
 			continue
 		}
 
@@ -166,87 +163,79 @@ func (f *PooledLDAPClientFactory) Initialize() (err error) {
 }
 
 // GetClient opens new client using the pool.
-func (f *PooledLDAPClientFactory) GetClient(opts ...LDAPClientFactoryOption) (conn ldap.Client, err error) {
+func (f *PooledLDAPClientFactory) GetClient(opts ...LDAPClientFactoryOption) (conn LDAPClient, err error) {
 	if len(opts) != 0 {
-		f.log.Trace("Creating new unpooled client")
+		f.log.Trace("Dialing new unpooled client")
 
-		return getLDAPClient(f.config.Address.String(), f.config.User, f.config.Password, f.config.Timeout, f.dialer, f.tls, f.config.StartTLS, f.opts, opts...)
+		return ldapDialBind(f.config.Address.String(), f.config.User, f.config.Password, f.config.Timeout, f.dialer, f.tls, f.config.StartTLS, f.opts, opts...)
 	}
 
 	return f.acquire(context.Background())
 }
 
-// The new function creates a pool based client. This function is not thread safe but is called from a function that requires holding a lock. The intended usage of this function IS thread safe.
-func (f *PooledLDAPClientFactory) new() (pooled *LDAPClientPooled, err error) {
-	var client ldap.Client
+// The dial function dials a new LDAPClient and wraps it as a PooledLDAPClient client.
+func (f *PooledLDAPClientFactory) dial() (pooled *PooledLDAPClient, err error) {
+	var client LDAPClient
 
-	f.log.Trace("Creating new pooled client")
+	f.log.Trace("Dialing new pooled client")
 
-	if client, err = getLDAPClient(f.config.Address.String(), f.config.User, f.config.Password, f.config.Timeout, f.dialer, f.tls, f.config.StartTLS, f.opts); err != nil {
+	if client, err = ldapDialBind(f.config.Address.String(), f.config.User, f.config.Password, f.config.Timeout, f.dialer, f.tls, f.config.StartTLS, f.opts); err != nil {
 		return nil, fmt.Errorf("error occurred establishing new client for the pool: %w", err)
 	}
 
-	pooled = &LDAPClientPooled{Client: client, log: f.log.WithField("client", f.next)}
+	f.mu.Lock()
+
+	pooled = &PooledLDAPClient{LDAPClient: client, log: f.log.WithField("client", f.next)}
 
 	f.next++
 
+	f.mu.Unlock()
+
 	pooled.log.Trace("New pooled client created")
 
 	return pooled, nil
 }
 
 // ReleaseClient returns a client using the pool or closes it.
-func (f *PooledLDAPClientFactory) ReleaseClient(client ldap.Client) (err error) {
+func (f *PooledLDAPClientFactory) ReleaseClient(client LDAPClient) (err error) {
 	f.log.Trace("Releasing Client")
 
-	f.mu.Lock()
-
-	defer f.mu.Unlock()
-
-	if f.closing {
-		f.log.Trace("Pool is closing, closing the released client")
+	if f.isClosing() {
+		f.log.Trace("Pooled/Unpooled Client is summarily being closed as the pool is closing or closed")
 
 		return client.Close()
 	}
 
-	var (
-		pool *LDAPClientPooled
-		ok   bool
-	)
-	if pool, ok = client.(*LDAPClientPooled); !ok {
+	switch c := client.(type) {
+	case *PooledLDAPClient:
+		return f.release(c)
+	default:
 		f.log.Trace("Unpooled client is being closed")
 
-		// Prevent extra or non-pool connections from being returned into the pool.
 		return client.Close()
 	}
+}
 
-	pool.log.Trace("Releasing pooled client")
+func (f *PooledLDAPClientFactory) release(client *PooledLDAPClient) (err error) {
+	client.log.Trace("Releasing pooled client")
 
 	select {
-	case f.pool <- pool:
-		pool.log.Trace("Returning pooled client to the pool")
-
+	case f.pool <- client:
 		return nil
 	default:
-		pool.log.Trace("Closing extra pooled client")
+		f.log.Trace("Pooled extra client is being closed")
 
 		return client.Close()
 	}
 }
 
-func (f *PooledLDAPClientFactory) acquire(ctx context.Context) (client *LDAPClientPooled, err error) {
+func (f *PooledLDAPClientFactory) acquire(ctx context.Context) (client *PooledLDAPClient, err error) {
 	f.log.Trace("Acquiring Client")
 
-	f.mu.Lock()
-
-	defer f.mu.Unlock()
-
-	if f.closing {
+	if f.isClosing() {
 		return nil, NewPoolCtxErr(fmt.Errorf("error acquiring client: the pool is closed"))
 	}
 
-	f.log.Trace("Timeout Started")
-
 	ctx, cancel := context.WithTimeout(ctx, f.config.Pooling.Timeout)
 	defer cancel()
 
@@ -255,31 +244,27 @@ func (f *PooledLDAPClientFactory) acquire(ctx context.Context) (client *LDAPClie
 		case <-ctx.Done():
 			return nil, NewPoolCtxErr(fmt.Errorf("error acquiring client: %w", ctx.Err()))
 		case client = <-f.pool:
-			if client.IsFailed() {
-				client.log.Trace("Client is closing or invalid")
-
-				if client, err = f.new(); err != nil {
-					f.log.WithError(err).Trace("Error acquiring new client")
-
-					time.Sleep(f.sleep)
+			if client.healthy() {
+				return client, nil
+			}
 
-					continue
-				}
+			client.log.Trace("Client is closing or invalid")
 
+			if client, err = f.dial(); err == nil {
 				client.log.Trace("New client acquired")
+
+				return client, nil
 			}
 
-			return client, nil
+			f.log.WithError(err).Trace("Error acquiring new client")
+
+			time.Sleep(f.sleep)
 		}
 	}
 }
 
 func (f *PooledLDAPClientFactory) Close() (err error) {
-	f.mu.Lock()
-
-	defer f.mu.Unlock()
-
-	f.closing = true
+	f.setClosing()
 
 	close(f.pool)
 
@@ -302,23 +287,41 @@ func (f *PooledLDAPClientFactory) Close() (err error) {
 	return nil
 }
 
-// LDAPClientPooled is a decorator for the ldap.Client which handles the pooling functionality. i.e. prevents the client
+func (f *PooledLDAPClientFactory) isClosing() bool {
+	f.mu.Lock()
+	defer f.mu.Unlock()
+
+	return f.closing
+}
+
+func (f *PooledLDAPClientFactory) setClosing() {
+	f.mu.Lock()
+	defer f.mu.Unlock()
+
+	f.closing = true
+}
+
+// PooledLDAPClient is a decorator for the LDAPClient which handles the pooling functionality. i.e. prevents the client
 // from being closed and instead relinquishes the connection back to the pool.
-type LDAPClientPooled struct {
-	ldap.Client
+type PooledLDAPClient struct {
+	LDAPClient
 
 	log *logrus.Entry
 }
 
-func (c *LDAPClientPooled) IsFailed() bool {
-	if c == nil || c.Client == nil {
-		return true
+func (c *PooledLDAPClient) healthy() bool {
+	if c == nil || c.LDAPClient == nil || c.IsClosing() {
+		return false
+	}
+
+	if _, err := c.WhoAmI(nil); err != nil {
+		return false
 	}
 
-	return c.IsClosing()
+	return true
 }
 
-func getLDAPClient(address, username, password string, timeout time.Duration, dialer LDAPClientDialer, tls *tls.Config, startTLS bool, dialerOpts []ldap.DialOpt, opts ...LDAPClientFactoryOption) (client ldap.Client, err error) {
+func ldapDialBind(address, username, password string, timeout time.Duration, dialer LDAPClientDialer, tls *tls.Config, startTLS bool, dialOpts []ldap.DialOpt, opts ...LDAPClientFactoryOption) (client LDAPClient, err error) {
 	config := &LDAPClientFactoryOptions{
 		Address:  address,
 		Username: username,
@@ -329,7 +332,7 @@ func getLDAPClient(address, username, password string, timeout time.Duration, di
 		opt(config)
 	}
 
-	if client, err = dialer.DialURL(config.Address, dialerOpts...); err != nil {
+	if client, err = dialer.DialURL(config.Address, dialOpts...); err != nil {
 		return nil, fmt.Errorf("error occurred dialing address: %w", err)
 	}
 
@@ -343,9 +346,11 @@ func getLDAPClient(address, username, password string, timeout time.Duration, di
 		}
 	}
 
-	if config.Password == "" {
+	//nolint:staticcheck // TODO: Add additional bind logic here, such as MD5Bind, NTLMBind, NTLMUnauthenticatedBind, etc.
+	switch {
+	case config.Password == "":
 		err = client.UnauthenticatedBind(config.Username)
-	} else {
+	default:
 		err = client.Bind(config.Username, config.Password)
 	}
 
@@ -355,5 +360,11 @@ func getLDAPClient(address, username, password string, timeout time.Duration, di
 		return nil, fmt.Errorf("error occurred performing bind: %w", err)
 	}
 
+	if _, err = client.WhoAmI(nil); err != nil {
+		_ = client.Close()
+
+		return nil, fmt.Errorf("error occurred performing whoami: %w", err)
+	}
+
 	return client, nil
 }
diff --git a/internal/authentication/ldap_user_provider.go b/internal/authentication/ldap_user_provider.go
index 7357c631c..9300f6d2f 100644
--- a/internal/authentication/ldap_user_provider.go
+++ b/internal/authentication/ldap_user_provider.go
@@ -86,7 +86,7 @@ func NewLDAPUserProviderWithFactory(config *schema.AuthenticationBackendLDAP, di
 // CheckUserPassword checks if provided password matches for the given user.
 func (p *LDAPUserProvider) CheckUserPassword(username string, password string) (valid bool, err error) {
 	var (
-		client, uclient ldap.Client
+		client, uclient LDAPClient
 		profile         *ldapUserProfile
 	)
 
@@ -120,7 +120,7 @@ func (p *LDAPUserProvider) CheckUserPassword(username string, password string) (
 // GetDetails retrieve the groups a user belongs to.
 func (p *LDAPUserProvider) GetDetails(username string) (details *UserDetails, err error) {
 	var (
-		client  ldap.Client
+		client  LDAPClient
 		profile *ldapUserProfile
 	)
 
@@ -157,7 +157,7 @@ func (p *LDAPUserProvider) GetDetails(username string) (details *UserDetails, er
 // GetDetailsExtended retrieves the UserDetailsExtended values.
 func (p *LDAPUserProvider) GetDetailsExtended(username string) (details *UserDetailsExtended, err error) {
 	var (
-		client  ldap.Client
+		client  LDAPClient
 		profile *ldapUserProfileExtended
 	)
 
@@ -246,7 +246,7 @@ func (p *LDAPUserProvider) GetDetailsExtended(username string) (details *UserDet
 // UpdatePassword update the password of the given user.
 func (p *LDAPUserProvider) UpdatePassword(username, password string) (err error) {
 	var (
-		client  ldap.Client
+		client  LDAPClient
 		profile *ldapUserProfile
 	)
 
@@ -274,7 +274,7 @@ func (p *LDAPUserProvider) UpdatePassword(username, password string) (err error)
 // ChangePassword is used to change a user's password but requires their old password to be successfully verified.
 func (p *LDAPUserProvider) ChangePassword(username, oldPassword string, newPassword string) (err error) {
 	var (
-		client  ldap.Client
+		client  LDAPClient
 		profile *ldapUserProfile
 	)
 
@@ -332,7 +332,7 @@ func (p *LDAPUserProvider) ChangePassword(username, oldPassword string, newPassw
 	return nil
 }
 
-func (p *LDAPUserProvider) setPassword(client ldap.Client, profile *ldapUserProfile, username, oldPassword, newPassword string) (err error) {
+func (p *LDAPUserProvider) setPassword(client LDAPClient, profile *ldapUserProfile, username, oldPassword, newPassword string) (err error) {
 	var controls []ldap.Control
 
 	switch {
@@ -371,7 +371,7 @@ func (p *LDAPUserProvider) setPassword(client ldap.Client, profile *ldapUserProf
 	}
 }
 
-func (p *LDAPUserProvider) search(client ldap.Client, request *ldap.SearchRequest) (result *ldap.SearchResult, err error) {
+func (p *LDAPUserProvider) search(client LDAPClient, request *ldap.SearchRequest) (result *ldap.SearchResult, err error) {
 	if result, err = client.Search(request); err != nil {
 		var e *ldap.Error
 
@@ -402,7 +402,7 @@ func (p *LDAPUserProvider) search(client ldap.Client, request *ldap.SearchReques
 
 func (p *LDAPUserProvider) searchReferral(referral string, request *ldap.SearchRequest, searchResult *ldap.SearchResult) (err error) {
 	var (
-		client ldap.Client
+		client LDAPClient
 		result *ldap.SearchResult
 	)
 
@@ -439,7 +439,7 @@ func (p *LDAPUserProvider) searchReferrals(request *ldap.SearchRequest, result *
 	return nil
 }
 
-func (p *LDAPUserProvider) getUserProfile(client ldap.Client, username string) (profile *ldapUserProfile, err error) {
+func (p *LDAPUserProvider) getUserProfile(client LDAPClient, username string) (profile *ldapUserProfile, err error) {
 	// Search for the given username.
 	request := ldap.NewSearchRequest(
 		p.usersBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
@@ -512,7 +512,7 @@ func (p *LDAPUserProvider) getUserProfileResultToProfile(username string, entry
 	return &userProfile, nil
 }
 
-func (p *LDAPUserProvider) getUserProfileExtended(client ldap.Client, username string) (profile *ldapUserProfileExtended, err error) {
+func (p *LDAPUserProvider) getUserProfileExtended(client LDAPClient, username string) (profile *ldapUserProfileExtended, err error) {
 	// Search for the given username.
 	request := ldap.NewSearchRequest(
 		p.usersBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
@@ -601,7 +601,7 @@ func (p *LDAPUserProvider) getUserProfileResultToProfileExtended(username string
 	return &userProfile, nil
 }
 
-func (p *LDAPUserProvider) getUserGroups(client ldap.Client, username string, profile *ldapUserProfile) (groups []string, err error) {
+func (p *LDAPUserProvider) getUserGroups(client LDAPClient, username string, profile *ldapUserProfile) (groups []string, err error) {
 	request := ldap.NewSearchRequest(
 		p.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
 		0, 0, false, p.resolveGroupsFilter(username, profile), p.groupsAttributes, nil,
@@ -626,7 +626,7 @@ func (p *LDAPUserProvider) getUserGroups(client ldap.Client, username string, pr
 	}
 }
 
-func (p *LDAPUserProvider) getUserGroupsRequestFilter(client ldap.Client, username string, _ *ldapUserProfile, request *ldap.SearchRequest) (groups []string, err error) {
+func (p *LDAPUserProvider) getUserGroupsRequestFilter(client LDAPClient, username string, _ *ldapUserProfile, request *ldap.SearchRequest) (groups []string, err error) {
 	var result *ldap.SearchResult
 
 	if result, err = p.search(client, request); err != nil {
@@ -642,7 +642,7 @@ func (p *LDAPUserProvider) getUserGroupsRequestFilter(client ldap.Client, userna
 	return groups, nil
 }
 
-func (p *LDAPUserProvider) getUserGroupsRequestMemberOf(client ldap.Client, username string, profile *ldapUserProfile, request *ldap.SearchRequest) (groups []string, err error) {
+func (p *LDAPUserProvider) getUserGroupsRequestMemberOf(client LDAPClient, username string, profile *ldapUserProfile, request *ldap.SearchRequest) (groups []string, err error) {
 	var result *ldap.SearchResult
 
 	if result, err = p.search(client, request); err != nil {
@@ -782,7 +782,7 @@ func (p *LDAPUserProvider) resolveGroupsFilter(input string, profile *ldapUserPr
 	return filter
 }
 
-func (p *LDAPUserProvider) modify(client ldap.Client, modifyRequest *ldap.ModifyRequest) (err error) {
+func (p *LDAPUserProvider) modify(client LDAPClient, modifyRequest *ldap.ModifyRequest) (err error) {
 	var result *ldap.ModifyResult
 	if result, err = client.ModifyWithResult(modifyRequest); err != nil {
 		var e *ldap.Error
@@ -808,7 +808,7 @@ func (p *LDAPUserProvider) modify(client ldap.Client, modifyRequest *ldap.Modify
 	p.log.Debugf("Attempting Modify on referred URL %s", result.Referral)
 
 	var (
-		clientRef ldap.Client
+		clientRef LDAPClient
 		errRef    error
 	)
 	if clientRef, errRef = p.factory.GetClient(WithAddress(result.Referral)); errRef != nil {
@@ -828,7 +828,7 @@ func (p *LDAPUserProvider) modify(client ldap.Client, modifyRequest *ldap.Modify
 	return nil
 }
 
-func (p *LDAPUserProvider) pwdModify(client ldap.Client, pwdModifyRequest *ldap.PasswordModifyRequest) (err error) {
+func (p *LDAPUserProvider) pwdModify(client LDAPClient, pwdModifyRequest *ldap.PasswordModifyRequest) (err error) {
 	var result *ldap.PasswordModifyResult
 	if result, err = client.PasswordModify(pwdModifyRequest); err != nil {
 		var e *ldap.Error
@@ -854,7 +854,7 @@ func (p *LDAPUserProvider) pwdModify(client ldap.Client, pwdModifyRequest *ldap.
 	p.log.Debugf("Attempting PwdModify ExOp (1.3.6.1.4.1.4203.1.11.1) on referred URL %s", result.Referral)
 
 	var (
-		clientRef ldap.Client
+		clientRef LDAPClient
 		errRef    error
 	)
 	if clientRef, errRef = p.factory.GetClient(WithAddress(result.Referral)); errRef != nil {
diff --git a/internal/authentication/ldap_user_provider_lifecycle.go b/internal/authentication/ldap_user_provider_lifecycle.go
index 8f45c99f2..e63562b61 100644
--- a/internal/authentication/ldap_user_provider_lifecycle.go
+++ b/internal/authentication/ldap_user_provider_lifecycle.go
@@ -20,7 +20,7 @@ func (p *LDAPUserProvider) StartupCheck() (err error) {
 		return err
 	}
 
-	var client ldap.Client
+	var client LDAPClient
 
 	if client, err = p.factory.GetClient(); err != nil {
 		return err
@@ -52,7 +52,7 @@ func (p *LDAPUserProvider) StartupCheck() (err error) {
 	return nil
 }
 
-func (p *LDAPUserProvider) getServerSupportedFeatures(client ldap.Client) (features LDAPSupportedFeatures, err error) {
+func (p *LDAPUserProvider) getServerSupportedFeatures(client LDAPClient) (features LDAPSupportedFeatures, err error) {
 	var (
 		request *ldap.SearchRequest
 		result  *ldap.SearchResult
diff --git a/internal/authentication/types.go b/internal/authentication/types.go
index fbe4a26a5..d77ddd62e 100644
--- a/internal/authentication/types.go
+++ b/internal/authentication/types.go
@@ -7,6 +7,7 @@ import (
 	"net/mail"
 	"net/url"
 
+	"github.com/go-ldap/ldap/v3"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/text/language"
 
@@ -322,3 +323,17 @@ func (e *PoolErr) Unwrap() error {
 func (e *PoolErr) IsDeadlineError() bool {
 	return e.isDeadlineError
 }
+
+type LDAPClient interface {
+	ldap.Client
+
+	GSSAPIBind(client ldap.GSSAPIClient, servicePrincipal, authzid string) (err error)
+	GSSAPIBindRequest(client ldap.GSSAPIClient, req *ldap.GSSAPIBindRequest) (err error)
+	GSSAPIBindRequestWithAPOptions(client ldap.GSSAPIClient, req *ldap.GSSAPIBindRequest, APOptions []int) (err error)
+	MD5Bind(host, username, password string) error
+	DigestMD5Bind(digestMD5BindRequest *ldap.DigestMD5BindRequest) (*ldap.DigestMD5BindResult, error)
+	NTLMChallengeBind(challenge *ldap.NTLMBindRequest) (result *ldap.NTLMBindResult, err error)
+	NTLMBindWithHash(domain, username, hash string) (err error)
+	NTLMBind(domain, username, password string) (err error)
+	WhoAmI(controls []ldap.Control) (result *ldap.WhoAmIResult, err error)
+}



Test patch:
diff --git a/internal/authentication/ldap_client_dialer_mock_test.go b/internal/authentication/ldap_client_dialer_mock_test.go
index 778b99f89..573e598c3 100644
--- a/internal/authentication/ldap_client_dialer_mock_test.go
+++ b/internal/authentication/ldap_client_dialer_mock_test.go
@@ -41,14 +41,14 @@ func (m *MockLDAPClientDialer) EXPECT() *MockLDAPClientDialerMockRecorder {
 }
 
 // DialURL mocks base method.
-func (m *MockLDAPClientDialer) DialURL(addr string, opts ...ldap.DialOpt) (ldap.Client, error) {
+func (m *MockLDAPClientDialer) DialURL(addr string, opts ...ldap.DialOpt) (LDAPClient, error) {
 	m.ctrl.T.Helper()
 	varargs := []any{addr}
 	for _, a := range opts {
 		varargs = append(varargs, a)
 	}
 	ret := m.ctrl.Call(m, "DialURL", varargs...)
-	ret0, _ := ret[0].(ldap.Client)
+	ret0, _ := ret[0].(LDAPClient)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
diff --git a/internal/authentication/ldap_client_factory_mock_test.go b/internal/authentication/ldap_client_factory_mock_test.go
index fe0a8c2e4..d50cd9fca 100644
--- a/internal/authentication/ldap_client_factory_mock_test.go
+++ b/internal/authentication/ldap_client_factory_mock_test.go
@@ -12,7 +12,6 @@ package authentication
 import (
 	reflect "reflect"
 
-	ldap "github.com/go-ldap/ldap/v3"
 	gomock "go.uber.org/mock/gomock"
 )
 
@@ -55,14 +54,14 @@ func (mr *MockLDAPClientFactoryMockRecorder) Close() *gomock.Call {
 }
 
 // GetClient mocks base method.
-func (m *MockLDAPClientFactory) GetClient(opts ...LDAPClientFactoryOption) (ldap.Client, error) {
+func (m *MockLDAPClientFactory) GetClient(opts ...LDAPClientFactoryOption) (LDAPClient, error) {
 	m.ctrl.T.Helper()
 	varargs := []any{}
 	for _, a := range opts {
 		varargs = append(varargs, a)
 	}
 	ret := m.ctrl.Call(m, "GetClient", varargs...)
-	ret0, _ := ret[0].(ldap.Client)
+	ret0, _ := ret[0].(LDAPClient)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
@@ -88,7 +87,7 @@ func (mr *MockLDAPClientFactoryMockRecorder) Initialize() *gomock.Call {
 }
 
 // ReleaseClient mocks base method.
-func (m *MockLDAPClientFactory) ReleaseClient(client ldap.Client) error {
+func (m *MockLDAPClientFactory) ReleaseClient(client LDAPClient) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ReleaseClient", client)
 	ret0, _ := ret[0].(error)
diff --git a/internal/authentication/ldap_client_mock_test.go b/internal/authentication/ldap_client_mock_test.go
index 055beecbe..2b216dda4 100644
--- a/internal/authentication/ldap_client_mock_test.go
+++ b/internal/authentication/ldap_client_mock_test.go
@@ -1,9 +1,9 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/go-ldap/ldap/v3 (interfaces: Client)
+// Source: github.com/authelia/authelia/v4/internal/authentication (interfaces: LDAPClient)
 //
 // Generated by this command:
 //
-//	mockgen -package authentication -destination ldap_client_mock_test.go -mock_names Client=MockLDAPClient github.com/go-ldap/ldap/v3 Client
+//	mockgen -package authentication -destination ldap_client_mock_test.go -mock_names LDAPClient=MockLDAPClient github.com/authelia/authelia/v4/internal/authentication LDAPClient
 //
 
 // Package authentication is a generated GoMock package.
@@ -19,7 +19,7 @@ import (
 	gomock "go.uber.org/mock/gomock"
 )
 
-// MockLDAPClient is a mock of Client interface.
+// MockLDAPClient is a mock of LDAPClient interface.
 type MockLDAPClient struct {
 	ctrl     *gomock.Controller
 	recorder *MockLDAPClientMockRecorder
@@ -114,6 +114,21 @@ func (mr *MockLDAPClientMockRecorder) Del(arg0 any) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Del", reflect.TypeOf((*MockLDAPClient)(nil).Del), arg0)
 }
 
+// DigestMD5Bind mocks base method.
+func (m *MockLDAPClient) DigestMD5Bind(digestMD5BindRequest *ldap.DigestMD5BindRequest) (*ldap.DigestMD5BindResult, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DigestMD5Bind", digestMD5BindRequest)
+	ret0, _ := ret[0].(*ldap.DigestMD5BindResult)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DigestMD5Bind indicates an expected call of DigestMD5Bind.
+func (mr *MockLDAPClientMockRecorder) DigestMD5Bind(digestMD5BindRequest any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DigestMD5Bind", reflect.TypeOf((*MockLDAPClient)(nil).DigestMD5Bind), digestMD5BindRequest)
+}
+
 // DirSync mocks base method.
 func (m *MockLDAPClient) DirSync(searchRequest *ldap.SearchRequest, flags, maxAttrCount int64, cookie []byte) (*ldap.SearchResult, error) {
 	m.ctrl.T.Helper()
@@ -172,6 +187,48 @@ func (mr *MockLDAPClientMockRecorder) ExternalBind() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExternalBind", reflect.TypeOf((*MockLDAPClient)(nil).ExternalBind))
 }
 
+// GSSAPIBind mocks base method.
+func (m *MockLDAPClient) GSSAPIBind(client ldap.GSSAPIClient, servicePrincipal, authzid string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GSSAPIBind", client, servicePrincipal, authzid)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// GSSAPIBind indicates an expected call of GSSAPIBind.
+func (mr *MockLDAPClientMockRecorder) GSSAPIBind(client, servicePrincipal, authzid any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GSSAPIBind", reflect.TypeOf((*MockLDAPClient)(nil).GSSAPIBind), client, servicePrincipal, authzid)
+}
+
+// GSSAPIBindRequest mocks base method.
+func (m *MockLDAPClient) GSSAPIBindRequest(client ldap.GSSAPIClient, req *ldap.GSSAPIBindRequest) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GSSAPIBindRequest", client, req)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// GSSAPIBindRequest indicates an expected call of GSSAPIBindRequest.
+func (mr *MockLDAPClientMockRecorder) GSSAPIBindRequest(client, req any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GSSAPIBindRequest", reflect.TypeOf((*MockLDAPClient)(nil).GSSAPIBindRequest), client, req)
+}
+
+// GSSAPIBindRequestWithAPOptions mocks base method.
+func (m *MockLDAPClient) GSSAPIBindRequestWithAPOptions(client ldap.GSSAPIClient, req *ldap.GSSAPIBindRequest, APOptions []int) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GSSAPIBindRequestWithAPOptions", client, req, APOptions)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// GSSAPIBindRequestWithAPOptions indicates an expected call of GSSAPIBindRequestWithAPOptions.
+func (mr *MockLDAPClientMockRecorder) GSSAPIBindRequestWithAPOptions(client, req, APOptions any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GSSAPIBindRequestWithAPOptions", reflect.TypeOf((*MockLDAPClient)(nil).GSSAPIBindRequestWithAPOptions), client, req, APOptions)
+}
+
 // GetLastError mocks base method.
 func (m *MockLDAPClient) GetLastError() error {
 	m.ctrl.T.Helper()
@@ -200,6 +257,20 @@ func (mr *MockLDAPClientMockRecorder) IsClosing() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsClosing", reflect.TypeOf((*MockLDAPClient)(nil).IsClosing))
 }
 
+// MD5Bind mocks base method.
+func (m *MockLDAPClient) MD5Bind(host, username, password string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "MD5Bind", host, username, password)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// MD5Bind indicates an expected call of MD5Bind.
+func (mr *MockLDAPClientMockRecorder) MD5Bind(host, username, password any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MD5Bind", reflect.TypeOf((*MockLDAPClient)(nil).MD5Bind), host, username, password)
+}
+
 // Modify mocks base method.
 func (m *MockLDAPClient) Modify(arg0 *ldap.ModifyRequest) error {
 	m.ctrl.T.Helper()
@@ -243,6 +314,49 @@ func (mr *MockLDAPClientMockRecorder) ModifyWithResult(arg0 any) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyWithResult", reflect.TypeOf((*MockLDAPClient)(nil).ModifyWithResult), arg0)
 }
 
+// NTLMBind mocks base method.
+func (m *MockLDAPClient) NTLMBind(domain, username, password string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NTLMBind", domain, username, password)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// NTLMBind indicates an expected call of NTLMBind.
+func (mr *MockLDAPClientMockRecorder) NTLMBind(domain, username, password any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMBind", reflect.TypeOf((*MockLDAPClient)(nil).NTLMBind), domain, username, password)
+}
+
+// NTLMBindWithHash mocks base method.
+func (m *MockLDAPClient) NTLMBindWithHash(domain, username, hash string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NTLMBindWithHash", domain, username, hash)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// NTLMBindWithHash indicates an expected call of NTLMBindWithHash.
+func (mr *MockLDAPClientMockRecorder) NTLMBindWithHash(domain, username, hash any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMBindWithHash", reflect.TypeOf((*MockLDAPClient)(nil).NTLMBindWithHash), domain, username, hash)
+}
+
+// NTLMChallengeBind mocks base method.
+func (m *MockLDAPClient) NTLMChallengeBind(challenge *ldap.NTLMBindRequest) (*ldap.NTLMBindResult, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NTLMChallengeBind", challenge)
+	ret0, _ := ret[0].(*ldap.NTLMBindResult)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// NTLMChallengeBind indicates an expected call of NTLMChallengeBind.
+func (mr *MockLDAPClientMockRecorder) NTLMChallengeBind(challenge any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NTLMChallengeBind", reflect.TypeOf((*MockLDAPClient)(nil).NTLMChallengeBind), challenge)
+}
+
 // NTLMUnauthenticatedBind mocks base method.
 func (m *MockLDAPClient) NTLMUnauthenticatedBind(domain, username string) error {
 	m.ctrl.T.Helper()
@@ -425,3 +539,18 @@ func (mr *MockLDAPClientMockRecorder) Unbind() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unbind", reflect.TypeOf((*MockLDAPClient)(nil).Unbind))
 }
+
+// WhoAmI mocks base method.
+func (m *MockLDAPClient) WhoAmI(controls []ldap.Control) (*ldap.WhoAmIResult, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "WhoAmI", controls)
+	ret0, _ := ret[0].(*ldap.WhoAmIResult)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// WhoAmI indicates an expected call of WhoAmI.
+func (mr *MockLDAPClientMockRecorder) WhoAmI(controls any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WhoAmI", reflect.TypeOf((*MockLDAPClient)(nil).WhoAmI), controls)
+}
diff --git a/internal/authentication/ldap_user_provider_test.go b/internal/authentication/ldap_user_provider_test.go
index 32cbda3a1..fc282fde5 100644
--- a/internal/authentication/ldap_user_provider_test.go
+++ b/internal/authentication/ldap_user_provider_test.go
@@ -56,13 +56,88 @@ func TestShouldCreateRawConnectionWhenSchemeIsLDAP(t *testing.T) {
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind)
+	whoami := mockClient.EXPECT().WhoAmI(nil)
+
+	gomock.InOrder(dialURL, setTimeout, clientBind, whoami)
 
 	_, err := provider.factory.GetClient()
 
 	require.NoError(t, err)
 }
 
+func TestShouldHandleWhoAmIError(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	config := &schema.AuthenticationBackendLDAP{
+		Address:  testLDAPAddress,
+		User:     "cn=admin,dc=example,dc=com",
+		Password: "password",
+		Timeout:  time.Second * 20,
+	}
+
+	mockDialer := NewMockLDAPClientDialer(ctrl)
+
+	factory := NewStandardLDAPClientFactory(config, nil, mockDialer)
+	mockClient := NewMockLDAPClient(ctrl)
+
+	provider := NewLDAPUserProviderWithFactory(
+		config,
+		false,
+		factory)
+
+	dialURL := mockDialer.EXPECT().DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()).Return(mockClient, nil)
+
+	setTimeout := mockClient.EXPECT().SetTimeout(gomock.Eq(time.Second * 20))
+
+	clientBind := mockClient.EXPECT().
+		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
+		Return(nil)
+
+	whoami := mockClient.EXPECT().WhoAmI(nil).Return(nil, fmt.Errorf("failed to whoami"))
+
+	gomock.InOrder(dialURL, setTimeout, clientBind, whoami, mockClient.EXPECT().Close())
+
+	_, err := provider.factory.GetClient()
+
+	assert.EqualError(t, err, "error occurred performing whoami: failed to whoami")
+}
+
+func TestShouldHandleBindError(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	config := &schema.AuthenticationBackendLDAP{
+		Address:  testLDAPAddress,
+		User:     "cn=admin,dc=example,dc=com",
+		Password: "password",
+		Timeout:  time.Second * 20,
+	}
+
+	mockDialer := NewMockLDAPClientDialer(ctrl)
+
+	factory := NewStandardLDAPClientFactory(config, nil, mockDialer)
+	mockClient := NewMockLDAPClient(ctrl)
+
+	provider := NewLDAPUserProviderWithFactory(
+		config,
+		false,
+		factory)
+
+	dialURL := mockDialer.EXPECT().DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()).Return(mockClient, nil)
+
+	setTimeout := mockClient.EXPECT().SetTimeout(gomock.Eq(time.Second * 20))
+
+	clientBind := mockClient.EXPECT().
+		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
+		Return(fmt.Errorf("failed to bind"))
+
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().Close())
+
+	_, err := provider.factory.GetClient()
+
+	assert.EqualError(t, err, "error occurred performing bind: failed to bind")
+}
 func TestShouldCreateTLSConnectionWhenSchemeIsLDAPS(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
@@ -89,7 +164,9 @@ func TestShouldCreateTLSConnectionWhenSchemeIsLDAPS(t *testing.T) {
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind)
+	whoami := mockClient.EXPECT().WhoAmI(nil)
+
+	gomock.InOrder(dialURL, setTimeout, clientBind, whoami)
 
 	_, err := provider.factory.GetClient()
 
@@ -358,6 +435,8 @@ func TestShouldCheckLDAPServerExtensions(t *testing.T) {
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
+	whoami := mockClient.EXPECT().WhoAmI(nil)
+
 	searchOIDs := mockClient.EXPECT().
 		Search(NewExtendedSearchRequestMatcher("(objectClass=*)", "", ldap.ScopeBaseObject, ldap.NeverDerefAliases, false, []string{ldapSupportedExtensionAttribute, ldapSupportedControlAttribute})).
 		Return(&ldap.SearchResult{
@@ -380,7 +459,7 @@ func TestShouldCheckLDAPServerExtensions(t *testing.T) {
 
 	clientClose := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchOIDs, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, whoami, searchOIDs, clientClose)
 
 	err := provider.StartupCheck()
 	assert.NoError(t, err)
@@ -430,6 +509,8 @@ func TestShouldCheckLDAPServerExtensionsPooled(t *testing.T) {
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
+	whoami := mockClient.EXPECT().WhoAmI(nil)
+
 	searchOIDs := mockClient.EXPECT().
 		Search(NewExtendedSearchRequestMatcher("(objectClass=*)", "", ldap.ScopeBaseObject, ldap.NeverDerefAliases, false, []string{ldapSupportedExtensionAttribute, ldapSupportedControlAttribute})).
 		Return(&ldap.SearchResult{
@@ -450,11 +531,15 @@ func TestShouldCheckLDAPServerExtensionsPooled(t *testing.T) {
 			},
 		}, nil)
 
+	whoamiSecond := mockClient.EXPECT().WhoAmI(nil)
+
 	gomock.InOrder(
 		dialURL,
 		setTimeout,
 		clientBind,
+		whoami,
 		mockClient.EXPECT().IsClosing().Return(false),
+		whoamiSecond,
 		searchOIDs,
 		mockClient.EXPECT().IsClosing().Return(false),
 		mockClient.EXPECT().Close().Return(fmt.Errorf("close error")),
@@ -505,6 +590,8 @@ func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntry(t
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
+	whoami := mockClient.EXPECT().WhoAmI(nil)
+
 	searchOIDs := mockClient.EXPECT().
 		Search(NewExtendedSearchRequestMatcher("(objectClass=*)", "", ldap.ScopeBaseObject, ldap.NeverDerefAliases, false, []string{ldapSupportedExtensionAttribute, ldapSupportedControlAttribute})).
 		Return(&ldap.SearchResult{
@@ -528,7 +615,7 @@ func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntry(t
 
 	clientClose := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchOIDs, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, whoami, searchOIDs, clientClose)
 
 	err := provider.StartupCheck()
 	assert.NoError(t, err)
@@ -599,7 +686,9 @@ func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntryPoo
 		dialURL,
 		setTimeout,
 		clientBind,
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().IsClosing().Return(false),
+		mockClient.EXPECT().WhoAmI(nil),
 		searchOIDs,
 		mockClient.EXPECT().IsClosing().Return(false),
 		mockClient.EXPECT().Close().Return(nil),
@@ -656,10 +745,14 @@ func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntryPoo
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
+	whoami := mockClient.EXPECT().WhoAmI(nil)
+
 	clientBindSecond := mockClientSecond.EXPECT().
 		Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 		Return(nil)
 
+	whoamiSecond := mockClientSecond.EXPECT().WhoAmI(nil)
+
 	searchOIDs := mockClientSecond.EXPECT().
 		Search(NewExtendedSearchRequestMatcher("(objectClass=*)", "", ldap.ScopeBaseObject, ldap.NeverDerefAliases, false, []string{ldapSupportedExtensionAttribute, ldapSupportedControlAttribute})).
 		Return(&ldap.SearchResult{
@@ -685,10 +778,12 @@ func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntryPoo
 		dialURL,
 		setTimeout,
 		clientBind,
+		whoami,
 		mockClient.EXPECT().IsClosing().Return(true),
 		dialURLSecond,
 		setTimeoutSecond,
 		clientBindSecond,
+		whoamiSecond,
 		searchOIDs,
 		mockClientSecond.EXPECT().IsClosing().Return(false),
 		mockClientSecond.EXPECT().Close().Return(nil),
@@ -761,7 +856,7 @@ func TestShouldCheckLDAPServerControlTypes(t *testing.T) {
 
 	clientClose := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchOIDs, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientClose)
 
 	err := provider.StartupCheck()
 	assert.NoError(t, err)
@@ -833,7 +928,9 @@ func TestShouldCheckLDAPServerControlTypesPooled(t *testing.T) {
 		dialURL,
 		setTimeout,
 		clientBind,
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().IsClosing().Return(false),
+		mockClient.EXPECT().WhoAmI(nil),
 		searchOIDs,
 		mockClient.EXPECT().IsClosing().Return(false),
 		clientClose,
@@ -906,7 +1003,7 @@ func TestShouldNotEnablePasswdModifyExtensionOrControlTypes(t *testing.T) {
 
 	clientClose := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchOIDs, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientClose)
 
 	assert.NoError(t, provider.StartupCheck())
 
@@ -981,7 +1078,9 @@ func TestShouldNotEnablePasswdModifyExtensionOrControlTypesPooled(t *testing.T)
 		dialURL,
 		setTimeout,
 		clientBind,
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().IsClosing().Return(false),
+		mockClient.EXPECT().WhoAmI(nil),
 		searchOIDs,
 		mockClient.EXPECT().IsClosing().Return(false),
 		clientClose,
@@ -1067,7 +1166,7 @@ func TestShouldReturnCheckServerSearchError(t *testing.T) {
 
 	clientClose := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchOIDs, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientClose)
 
 	err := provider.StartupCheck()
 	assert.EqualError(t, err, "error occurred during RootDSE search: could not perform the search")
@@ -1119,7 +1218,9 @@ func TestShouldReturnCheckServerSearchErrorPooled(t *testing.T) {
 		dialURL,
 		setTimeout,
 		clientBind,
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().IsClosing().Return(false),
+		mockClient.EXPECT().WhoAmI(nil),
 		searchOIDs,
 		mockClient.EXPECT().IsClosing().Return(false),
 		clientClose,
@@ -1173,7 +1274,7 @@ func TestShouldPermitRootDSEFailure(t *testing.T) {
 
 	clientClose := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchOIDs, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientClose)
 
 	assert.NoError(t, provider.StartupCheck())
 }
@@ -1223,7 +1324,9 @@ func TestShouldPermitRootDSEFailurePooled(t *testing.T) {
 		dialURL,
 		setTimeout,
 		clientBind,
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().IsClosing().Return(false),
+		mockClient.EXPECT().WhoAmI(nil),
 		searchOIDs,
 		mockClient.EXPECT().IsClosing().Return(false),
 		clientClose,
@@ -1341,7 +1444,7 @@ func TestShouldReturnEmailWhenAttributeSameAsUsername(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -1414,7 +1517,7 @@ func TestShouldReturnUsernameAndBlankDisplayNameWhenAttributesTheSame(t *testing
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -1495,7 +1598,7 @@ func TestShouldReturnBlankEmailAndDisplayNameWhenAttrsLenZero(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -1656,7 +1759,7 @@ func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -1910,7 +2013,7 @@ func TestLDAPUserProvider_GetDetailsExtended_ShouldPass(t *testing.T) {
 
 	searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
 
-	gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, searchGroup, connClose)
+	gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroup, connClose)
 
 	enAU := language.MustParse("en-AU")
 	website, _ := url.Parse("https://authelia.com")
@@ -2073,7 +2176,7 @@ func TestLDAPUserProvider_GetDetailsExtended_ShouldParseError(t *testing.T) {
 					},
 				}, nil)
 
-			gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, connClose)
+			gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, connClose)
 
 			details, err := provider.GetDetailsExtended("john")
 			assert.Nil(t, details)
@@ -2157,7 +2260,7 @@ func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadPictureURL(t *testing
 
 	searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
 
-	gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, searchGroup, connClose)
+	gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroup, connClose)
 
 	details, err := provider.GetDetailsExtended("john")
 	assert.Nil(t, details)
@@ -2239,7 +2342,7 @@ func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadProfileURL(t *testing
 
 	searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
 
-	gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, searchGroup, connClose)
+	gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroup, connClose)
 
 	details, err := provider.GetDetailsExtended("john")
 	assert.Nil(t, details)
@@ -2321,7 +2424,7 @@ func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadWebsiteURL(t *testing
 
 	searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
 
-	gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, searchGroup, connClose)
+	gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroup, connClose)
 
 	details, err := provider.GetDetailsExtended("john")
 	assert.Nil(t, details)
@@ -2403,7 +2506,7 @@ func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadLocale(t *testing.T)
 
 	searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
 
-	gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, searchGroup, connClose)
+	gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroup, connClose)
 
 	details, err := provider.GetDetailsExtended("john")
 	assert.Nil(t, details)
@@ -2450,7 +2553,7 @@ func TestLDAPUserProvider_GetDetails_ShouldReturnOnUserError(t *testing.T) {
 		Search(gomock.Any()).
 		Return(nil, fmt.Errorf("failed to search"))
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, clientClose)
 
 	details, err := provider.GetDetails("john")
 	assert.Nil(t, details)
@@ -2584,7 +2687,7 @@ func TestLDAPUserProvider_GetDetailsExtendedShouldReturnOnUserError(t *testing.T
 		Search(gomock.Any()).
 		Return(nil, fmt.Errorf("failed to search"))
 
-	gomock.InOrder(dialURL, setTimeout, connBind, searchProfile, connClose)
+	gomock.InOrder(dialURL, setTimeout, connBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, connClose)
 
 	details, err := provider.GetDetailsExtended("john")
 	assert.Nil(t, details)
@@ -2655,7 +2758,7 @@ func TestLDAPUserProvider_GetDetails_ShouldReturnOnGroupsError(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 
@@ -2718,7 +2821,7 @@ func TestShouldNotCrashWhenEmailsAreNotRetrievedFromLDAP(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -2783,7 +2886,7 @@ func TestShouldUnauthenticatedBind(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -2857,7 +2960,7 @@ func TestShouldReturnUsernameFromLDAP(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -2946,7 +3049,7 @@ func TestShouldReturnUsernameFromLDAPSearchModeMemberOfRDN(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -3033,7 +3136,7 @@ func TestShouldReturnUsernameFromLDAPSearchModeMemberOfDN(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -3120,7 +3223,7 @@ func TestShouldReturnErrSearchMemberOf(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	assert.Nil(t, details)
@@ -3194,7 +3297,7 @@ func TestShouldReturnErrUnknownSearchMode(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, clientClose)
 
 	details, err := provider.GetDetails("john")
 	assert.Nil(t, details)
@@ -3307,7 +3410,7 @@ func TestShouldSkipEmptyAttributesSearchModeMemberOf(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 
@@ -3420,7 +3523,7 @@ func TestShouldSkipEmptyAttributesSearchModeFilter(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 
@@ -3497,7 +3600,7 @@ func TestShouldSkipEmptyGroupsResultMemberOf(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -3587,7 +3690,7 @@ func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndNoResult(t *testing.
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, dialURLReferral, setTimeoutReferral, clientBindReferral, searchProfileReferral, clientCloseReferral, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), searchProfileReferral, clientCloseReferral, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -3639,7 +3742,7 @@ func TestShouldReturnErrorWhenUntypedReferralError(t *testing.T) {
 		Search(gomock.Any()).
 		Return(&ldap.SearchResult{Referrals: []string{"ldap://192.168.0.1"}}, fmt.Errorf("referral"))
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, clientClose)
 
 	details, err := provider.GetDetails("john")
 	assert.Nil(t, details)
@@ -3689,7 +3792,7 @@ func TestShouldReturnDialErrDuringReferralSearchUsernameFromLDAPWithReferralsInE
 
 	dialURLReferral := mockDialer.EXPECT().DialURL("ldap://192.168.0.1", gomock.Any()).Return(nil, fmt.Errorf("failed to connect"))
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, dialURLReferral, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, dialURLReferral, clientClose)
 
 	details, err := provider.GetDetails("john")
 
@@ -3753,7 +3856,7 @@ func TestShouldReturnSearchErrDuringReferralSearchUsernameFromLDAPWithReferralsI
 		Search(gomock.Any()).
 		Return(nil, fmt.Errorf("not found"))
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, dialURLReferral, setTimeoutReferral, clientBindReferral, searchProfileReferral, clientCloseReferral, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), searchProfileReferral, clientCloseReferral, clientClose)
 
 	details, err := provider.GetDetails("john")
 
@@ -3802,7 +3905,7 @@ func TestShouldNotReturnUsernameFromLDAPWithReferralsInErrorAndReferralsNotPermi
 		Search(gomock.Any()).
 		Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultReferral, Err: errors.New("referral"), Packet: &testBERPacketReferral})
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, clientClose)
 
 	details, err := provider.GetDetails("john")
 	assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: LDAP Result Code 10 \"Referral\": referral")
@@ -3889,7 +3992,7 @@ func TestShouldReturnUsernameFromLDAPWithReferralsErr(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, searchProfile, dialURLReferral, setTimeoutReferral, clientBindReferral, searchProfileReferral, clientCloseReferral, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), searchProfileReferral, clientCloseReferral, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -3958,7 +4061,7 @@ func TestShouldNotUpdateUserPasswordConnect(t *testing.T) {
 
 	clientCloseOIDs := mockClient.EXPECT().Close()
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL)
 
 	require.NoError(t, provider.StartupCheck())
 
@@ -4035,7 +4138,7 @@ func TestShouldNotUpdateUserPasswordGetDetails(t *testing.T) {
 		Search(gomock.Any()).
 		Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultProtocolError, Err: errors.New("permission error")})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, clientClose)
 
 	require.NoError(t, provider.StartupCheck())
 
@@ -4142,7 +4245,7 @@ func TestShouldUpdateUserPassword(t *testing.T) {
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -4253,7 +4356,7 @@ func TestShouldUpdateUserPasswordMSAD(t *testing.T) {
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -4384,7 +4487,7 @@ func TestShouldUpdateUserPasswordMSADWithReferrals(t *testing.T) {
 		Modify(modifyRequest).
 		Return(nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, dialURLReferral, setTimeoutReferral, clientBindReferral, modifyReferral, clientCloseReferral, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), modifyReferral, clientCloseReferral, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -4496,7 +4599,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsButIncorrectErrorType(t *testi
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{Referral: "ldap://192.168.0.1"}, fmt.Errorf("referral"))
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, clientClose)
 
 	require.NoError(t, provider.StartupCheck())
 	assert.EqualError(t, provider.UpdatePassword("john", "password"), "unable to update password. Cause: referral")
@@ -4609,7 +4712,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsButIncorrectResultCode(t *test
 			Packet:     &testBERPacketReferral,
 		})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, clientClose)
 
 	require.NoError(t, provider.StartupCheck())
 
@@ -4728,7 +4831,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralConnectErr(t *test
 
 	dialURLReferral := mockDialer.EXPECT().DialURL("ldap://192.168.0.1", gomock.Any()).Return(nil, errors.New("tcp timeout"))
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, dialURLReferral, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, dialURLReferral, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -4866,7 +4969,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralModifyErr(t *testi
 			Packet:     &testBERPacketReferral,
 		})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, dialURLReferral, setTimeoutReferral, clientBindReferral, modifyReferral, clientCloseReferral, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), modifyReferral, clientCloseReferral, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -4982,7 +5085,7 @@ func TestShouldUpdateUserPasswordMSADWithoutReferrals(t *testing.T) {
 			Packet:     &testBERPacketReferral,
 		})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, modify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, modify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5090,7 +5193,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtension(t *testing.T) {
 		PasswordModify(pwdModifyRequest).
 		Return(nil, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5220,7 +5323,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferrals(t *testing.T
 		PasswordModify(pwdModifyRequest).
 		Return(&ldap.PasswordModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, dialURLReferral, setTimeoutReferral, clientBindReferral, passwdModifyReferral, clientCloseReferral, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), passwdModifyReferral, clientCloseReferral, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5335,7 +5438,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsButBadResultC
 			Packet:     &testBERPacketReferral,
 		})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5445,7 +5548,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsButBadErrorTy
 			Referral: "ldap://192.168.0.1",
 		}, fmt.Errorf("referral"))
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5559,7 +5662,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithoutReferrals(t *testin
 			Packet:     &testBERPacketReferral,
 		})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5676,7 +5779,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralConne
 
 	dialURLReferral := mockDialer.EXPECT().DialURL("ldap://192.168.0.1", gomock.Any()).Return(nil, errors.New("tcp timeout"))
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, dialURLReferral, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, dialURLReferral, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5810,7 +5913,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralPassw
 			Packet:     &testBERPacketReferral,
 		})
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, dialURLReferral, setTimeoutReferral, clientBindReferral, passwdModifyReferral, clientCloseReferral, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, dialURLReferral, setTimeoutReferral, clientBindReferral, mockClientReferral.EXPECT().WhoAmI(nil), passwdModifyReferral, clientCloseReferral, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -5924,7 +6027,7 @@ func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHints(t *testing
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -6038,7 +6141,7 @@ func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHintsDeprecated(
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -6152,7 +6255,7 @@ func TestShouldUpdateUserPasswordActiveDirectory(t *testing.T) {
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -6262,7 +6365,7 @@ func TestShouldUpdateUserPasswordBasic(t *testing.T) {
 		ModifyWithResult(modifyRequest).
 		Return(&ldap.ModifyResult{}, nil)
 
-	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, searchProfile, passwdModify, clientClose)
+	gomock.InOrder(dialURLOIDs, setTimeoutOIDs, clientBindOIDs, mockClient.EXPECT().WhoAmI(nil), searchOIDs, clientCloseOIDs, dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, passwdModify, clientClose)
 
 	err := provider.StartupCheck()
 	require.NoError(t, err)
@@ -6328,7 +6431,7 @@ func TestShouldReturnErrorWhenMultipleUsernameAttributes(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -6396,7 +6499,7 @@ func TestShouldReturnErrorWhenZeroUsernameAttributes(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -6460,7 +6563,7 @@ func TestShouldReturnErrorWhenUsernameAttributeNotReturned(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -6545,7 +6648,7 @@ func TestShouldReturnErrorWhenMultipleUsersFound(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -6613,7 +6716,7 @@ func TestShouldReturnErrorWhenNoDN(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, clientBind, search)
+	gomock.InOrder(dialURL, setTimeout, clientBind, mockClient.EXPECT().WhoAmI(nil), search)
 
 	client, err := provider.factory.GetClient()
 	assert.NoError(t, err)
@@ -6655,6 +6758,7 @@ func TestShouldCheckValidUserPassword(t *testing.T) {
 		mockClient.EXPECT().
 			Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 			Return(nil),
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().
 			Search(gomock.Any()).
 			Return(&ldap.SearchResult{
@@ -6683,6 +6787,7 @@ func TestShouldCheckValidUserPassword(t *testing.T) {
 		mockClient.EXPECT().
 			Bind(gomock.Eq("uid=test,dc=example,dc=com"), gomock.Eq("password")).
 			Return(nil),
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().Close().Times(2),
 	)
 
@@ -6764,6 +6869,7 @@ func TestShouldNotCheckValidUserPasswordWithGetProfileError(t *testing.T) {
 		mockClient.EXPECT().
 			Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 			Return(nil),
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().
 			Search(gomock.Any()).
 			Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultBusy, Err: errors.New("directory server busy")}),
@@ -6807,6 +6913,7 @@ func TestShouldCheckInvalidUserPassword(t *testing.T) {
 		mockClient.EXPECT().
 			Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 			Return(nil),
+		mockClient.EXPECT().WhoAmI(nil),
 		mockClient.EXPECT().
 			Search(gomock.Any()).
 			Return(&ldap.SearchResult{
@@ -6913,7 +7020,7 @@ func TestShouldCallStartTLSWhenEnabled(t *testing.T) {
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, connStartTLS, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, connStartTLS, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -7049,7 +7156,7 @@ func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue(t *testing.T
 			},
 		}, nil)
 
-	gomock.InOrder(dialURL, setTimeout, connStartTLS, clientBind, searchProfile, searchGroups, clientClose)
+	gomock.InOrder(dialURL, setTimeout, connStartTLS, clientBind, mockClient.EXPECT().WhoAmI(nil), searchProfile, searchGroups, clientClose)
 
 	details, err := provider.GetDetails("john")
 	require.NoError(t, err)
@@ -7147,6 +7254,8 @@ func TestLDAPUserProviderChangePasswordErrors(t *testing.T) {
 					Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")).
 					Return(nil)
 
+				mockClient.EXPECT().WhoAmI(nil)
+
 				mockClient.EXPECT().
 					Search(gomock.Any()).
 					Return(nil, errors.New("search error"))
@@ -7186,9 +7295,13 @@ func TestLDAPUserProviderChangePasswordErrors(t *testing.T) {
 				mockClient.EXPECT().Bind("cn=admin,dc=example,dc=com", "password").
 					Return(nil)
 
+				mockClient.EXPECT().WhoAmI(nil)
+
 				mockClient.EXPECT().Bind("cn=admin,dc=example,dc=com", "password").
 					Return(nil)
 
+				mockClient.EXPECT().WhoAmI(nil)
+
 				mockClient.EXPECT().Search(gomock.Any()).
 					Return(&ldap.SearchResult{
 						Entries: []*ldap.Entry{
@@ -7246,6 +7359,7 @@ func TestLDAPUserProviderChangePasswordErrors(t *testing.T) {
 
 				mockClient.EXPECT().Bind("cn=admin,dc=example,dc=com", "password").
 					Return(nil).Times(2)
+				mockClient.EXPECT().WhoAmI(nil).Times(3)
 
 				mockClient.EXPECT().Search(gomock.Any()).
 					Return(&ldap.SearchResult{
@@ -7286,6 +7400,7 @@ func TestLDAPUserProviderChangePasswordErrors(t *testing.T) {
 
 				mockClient.EXPECT().Bind("cn=admin,dc=example,dc=com", "password").
 					Return(nil).Times(2)
+				mockClient.EXPECT().WhoAmI(nil).Times(3)
 
 				mockClient.EXPECT().Search(gomock.Any()).
 					Return(&ldap.SearchResult{