UT015005: Error invoking method sessionDestroyed on listener class org.springframework.security.web.session.HttpSessionEventPublisher

I am developing an R Shiny application with integration of Keycloak + shinyproxy + nginx. I would like to preface by saying that this is my first experience with such a setup, as my background is in Data Science rather than web development (most of it was generated by AI). At the moment, I have a working version of authentication: when I navigate to localhost, if I have already logged in, I am redirected to my R Shiny application; if not, I am redirected to authenticate via Keycloak, after which I enter the application.

The problem occurs when a user wants to log out. Essentially, the user logs out and is redirected back to the login page, which is correct, but in my shinyproxy logs I see the following:

2025-03-06 12:59:44 2025-03-06T08:59:44.394Z INFO 1 --- [ XNIO-1 task-5] e.o.containerproxy.service.UserService : User logged out [user: testuser]
2025-03-06 12:59:44 2025-03-06T08:59:44.410Z ERROR 1 --- [ XNIO-1 task-5] io.undertow.servlet.request : UT015005: Error invoking method sessionDestroyed on listener class org.springframework.security.web.session.HttpSessionEventPublisher
2025-03-06 12:59:44
2025-03-06 12:59:44 java.util.ConcurrentModificationException: null
..................

After some trial and error, I discovered that this error disappears if I first stop the R Shiny application using the developer nav-bar and only then log out (or if I manage to log out before my application has fully loaded).

In that case, my logs look like this:

2025-03-06 13:09:36 2025-03-06T09:09:36.270Z INFO 1 --- [ XNIO-1 task-5] e.o.containerproxy.service.UserService : User logged in [user: testuser]
2025-03-06 13:09:36 2025-03-06T09:09:36.821Z INFO 1 --- [ProxyService-16] e.o.containerproxy.service.ProxyService : [user=testuser proxyId=7fa2693f-9326-40c7-b830-190a3d13d582 specId=dashboard] Starting proxy
2025-03-06 13:09:37 2025-03-06T09:09:37.151Z INFO 1 --- [ProxyService-16] o.m.docker.client.DefaultDockerClient : Starting container with Id: 56c796cb02b0faef661d789ad070364537da74ba35bd39d66194b8282680711b
2025-03-06 13:09:40 2025-03-06T09:09:40.128Z INFO 1 --- [ProxyService-16] e.o.containerproxy.service.ProxyService : [user=testuser proxyId=7fa2693f-9326-40c7-b830-190a3d13d582 specId=dashboard] Proxy activated
2025-03-06 13:09:44 2025-03-06T09:09:44.154Z INFO 1 --- [ XNIO-1 task-4] e.o.containerproxy.service.ProxyService : [user=testuser proxyId=7fa2693f-9326-40c7-b830-190a3d13d582 specId=dashboard] Proxy being stopped by user testuser
2025-03-06 13:09:44 2025-03-06T09:09:44.668Z INFO 1 --- [ProxyService-16] e.o.containerproxy.service.ProxyService : [user=testuser proxyId=7fa2693f-9326-40c7-b830-190a3d13d582 specId=dashboard] Proxy released
2025-03-06 13:09:45 2025-03-06T09:09:45.315Z INFO 1 --- [ XNIO-1 task-4] e.o.containerproxy.service.UserService : User logged out [user: testuser]

However, I do not consider this a solution to my problem, since in the future I plan to disable this nav-bar and use my own custom one within the R Shiny application.

This is my current Keycloak settings:

And my code:

Applcation.yml:

proxy:
  title: "ShinyProxy"
  landing-page: /app/dashboard
  base-url: /
  hide-navbar: false
  admin-groups: [ "admin" ]

  # -- Auth Settings --
  authentication: openid
  openid:
    # Change these URLs to use internal Docker network names or consistent external URLs
    issuer: http://keycloak:8080/auth/realms/shinyrealm
    auth-url: http://localhost/auth/realms/shinyrealm/protocol/openid-connect/auth
    token-url: http://keycloak:8080/auth/realms/shinyrealm/protocol/openid-connect/token
    jwks-url: http://keycloak:8080/auth/realms/shinyrealm/protocol/openid-connect/certs
    logout-url: http://localhost/auth/realms/shinyrealm/protocol/openid-connect/logout?id_token_hint=#{oidcUser.idToken.tokenValue}&post_logout_redirect_uri=http%3A%2F%2Flocalhost
    client-id: shinyproxy
    client-secret: NbSFsFa5Wy1z03T7vFcl6QgJxLpgs16L
    username-attribute: preferred_username

  # -- Prevent ShinyProxy from killing your app --
  heartbeat-timeout: 180000000

  # -- Docker settings (launch containers for each Shiny app) --
  docker:
    url: "http://host.docker.internal:2375"
    internal-networking: true
    auto-remove: true
    container-network: shiny-network

  # -- List of Shiny apps to launch --
  specs:
  - id: dashboard
    display-name: "Test"
    container-image: shiny-app1:latest
    container-network: shiny-network
    container-port: 80
    unused-timeout: 0

docker-compose.yml:

services:
  keycloak:
    image: quay.io/keycloak/keycloak:latest
    container_name: keycloak
    environment:
      PROXY_ADDRESS_FORWARDING: "true"
      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: admin
    command: ["start-dev", "--http-relative-path=/auth"]
    networks:
      - shiny-network

  shinyproxy:
    image: openanalytics/shinyproxy:latest
    container_name: shinyproxy
    depends_on:
      - keycloak
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./application.yml:/opt/shinyproxy/application.yml
    networks:
      - shiny-network

  nginx:
    image: nginx:latest
    container_name: nginx
    depends_on:
      - shinyproxy
      - keycloak
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - shiny-network

networks:
  shiny-network:
    name: shiny-network
    driver: bridge

nginx.conf:

  server {
    listen 80;
    server_name localhost;
    
    # Match both /app and /app/
    location ~ ^/app/?$ {
        return 301 $scheme://$host/app/dashboard;
    }
    
    # Forward requests to ShinyProxy
    location / {
        proxy_pass http://shinyproxy:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Prefix /;
        
        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600;
    }
    
    # Keycloak endpoints
    location /auth/ {
        proxy_pass http://keycloak:8080/auth/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

For other users, see UT015005: Error invoking method sessionDestroyed on listener class org.springframework.security.web.session.HttpSessionEventPublisher · Issue #553 · openanalytics/shinyproxy · GitHub

FYI we are working on a new release that will include this fix.