Can't fetch user info from Keycloak using Python on docker compose

I need to run, from docker compose, three containers: a fastapi server, a keycloack server and a postgres database. This used to work, but now I can’t make requests to my endpoints in swagger anymore, despite being authenticated. Maybe it’s been caused by some new release of the keycloak image used. I noted that authorization is now OpenIdConnect (OAuth2, authorization_code with PKCE) instead of previous OpenIdConnect (OAuth2, authorization_code)`.

My docker-compose.yaml:

version: '3.9'

services:
    web:
        build: ./foo
        command: uvicorn main:app --reload --workers 1 --host 0.0.0.0 --port 8000
        volumes:
            - ./foo:/usr/src
        ports:
            - 8000:8000
        depends_on:
            - db
            - kc
        environment:
            BAR_ENV: local
            LOGGER_NAME: local
            BAR_DB_LOCAL_USERPASS: bar:bar
            BAR_DB_LOCAL_DB_NAME: bar
            BAR_DB_LOCAL_HOST: localhost:5438
            BAR_HOSTNAME: bar.local
            BAR_AUTH_URL: http://auth.bar.local:8087
            BAR_FRONT_URL: bar.local:3000
    kc:
        image: quay.io/keycloak/keycloak-x:latest
        command: start-dev --db=postgres --db-url-host=$$DB_HOST --db-url-database=$$DB_DATABASE --db-username=$$DB_USER --db-password=$$DB_PASS --http-port=8087
        environment:
            KEYCLOAK_ADMIN: admin
            KEYCLOAK_ADMIN_PASSWORD: admin
            DB_HOST: db
            DB_DATABASE: &KC_DB_DB keycloak
            DB_USER: &KC_DB_USER keycloak
            DB_PASS: &KC_DB_PASS keycloak
        domainname: auth.bar.local
        ports:
            - 8087:8087
        depends_on:
            - db
        volumes:
            - ./resources/keycloak-themes:/opt/keycloak/themes/theme
    db:
        image: postgres:14
        environment:
            POSTGRES_DB: postgres
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: postgres
            KC_DB_DB: *KC_DB_DB
            KC_DB_USER: *KC_DB_USER
            KC_DB_PASS: *KC_DB_PASS
            BAR_DB_DB: bar
            BAR_DB_USER: bar
            BAR_DB_PASS: bar
        ports:
            - 5438:5432
        volumes:
            - ./data/pg-data:/var/lib/postgresql/data
            - ./resources/init-kc-db.sh:/docker-entrypoint-initdb.d/init-kc-db.sh
            - ./resources/init-bar-db.sh:/docker-entrypoint-initdb.d/init-bar-db.sh

I’m able to access http://<realm>.bar.local:8000/docs from the browser and to authenticate on OpenIdConnect (OAuth2, authorization_code with PKCE). It redirects me to keycloak login page and, then, back to swagger. But, if I try one of my endpoints in swagger, for example, /whoami, I get a 500 internal server error.

Logs from web_1 service:

web_1      | keycloak.exceptions.KeycloakConnectionError: Can't connect to server (HTTPConnectionPool(host='auth.bar.local', port=8087): Max retries exceeded with url: /realms/<realm>/protocol/openid-connect/userinfo (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fd38041a6b0>: Failed to establish a new connection: [Errno 111] Connection refused')))
web_1      | {"asctime": "2022-04-26 11:31:54,929", "threadName": "MainThread", "filename": "httptools_impl.py", "lineno": 437, "message": "172.18.0.1:63454 - \"GET /api/v1_0/whoami HTTP/1.1\" 500", "severity": "INFO"}

the error above occurs in my keycloak_auth.py (I’m using python-keycloak==0.27.0), when it tries to fetch user info from self.kc_clients[org]:

class OpenIdConnectMultipleViaKeycloak(SecurityBase):

    def __init__(
            self, *, internal_well_known_url: str, server_url: str,
            client_template: str, realm_template: str):

        self.model = OpenIdConnectModel(
            openIdConnectUrl=internal_well_known_url)
        self.scheme_name = 'OpenIdConnect'
        self.auto_error = True
        self.server_url = server_url
        self.client_template = client_template
        self.realm_template = realm_template
        self.kc_clients = {}

    async def __call__(self, request: Request) -> Optional[str]:

        org = get_org_from_host(request.base_url.hostname)

        if org not in self.kc_clients:

            self.kc_clients[org] = KeycloakOpenID(
                server_url=self.server_url,
                client_id=self.client_template.format(org=org),
                realm_name=self.realm_template.format(org=org))

        authorization: str = request.headers.get("Authorization")

        if not authorization:
            raise HTTPException(
                status_code=HTTP_403_FORBIDDEN, detail="Not authenticated")

        try:
            userinfo = self.kc_clients[org].userinfo(
                authorization.replace('Bearer ', ''))

            userinfo['keycloak_realm'] = org
        except KeycloakGetError as e:
            raise HTTPException(
                status_code=HTTP_403_FORBIDDEN, detail=str(e))

        return userinfo

Inspecting kc_1 service from inside container:

[root@e3e5d33ce08b /]# nmap -O localhost
Starting Nmap 7.70 ( https://nmap.org ) at 2022-04-26 17:01 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000080s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 999 closed ports
PORT     STATE SERVICE
8087/tcp open  simplifymedia
Device type: general purpose
Running: Linux 2.6.X
OS CPE: cpe:/o:linux:linux_kernel:2.6.32
OS details: Linux 2.6.32
Network Distance: 0 hops

OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 4.21 seconds

and

root@e3e5d33ce08b /]# netstat -nlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:8087            0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.11:41567        0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:37927         0.0.0.0:*               LISTEN      -                   
udp        0      0 127.0.0.11:57222        0.0.0.0:*                           -                   
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
Active Bluetooth connections (only servers)
Proto  Destination       Source            State         PSM DCID   SCID      IMTU    OMTU Security
Proto  Destination       Source            State     Channel
[root@e3e5d33ce08b /]# 

Inspecting domain auth.bar.local from web_1 container:

root@0cf70e1cef7f:/usr/src/barz# nmap -p 8087 auth.bar.local
Starting Nmap 7.80 ( https://nmap.org ) at 2022-04-26 17:02 UTC
Nmap scan report for auth.bar.local (127.0.0.1)
Host is up (0.000068s latency).
rDNS record for 127.0.0.1: localhost

PORT     STATE  SERVICE
8087/tcp closed simplifymedia

Nmap done: 1 IP address (1 host up) scanned in 15.06 seconds

It seems that domainname is reachable from other containers and from outside, but requests made to port 8087 from others services. I’ve tried to ps aux | grep start-dev and it is running under PID 1. I can even wget it inside kc_1 container and receive a response. I also tried code proposed in networking - Make one Docker Compose service know the domain name of another - Stack Overflow , but the behavior did not change.

What am I supposed to do to successfully get http://auth.bar.local:8087/realms/<realm>/protocol/openid-connect/userinfo using docker compose?