'Spring Security 5 OAuth2 App with Keycloack 17 gets "Connection Refused" when run in Docker container with docker-compose

I have a super simple Spring Boot app with Spring Security 5 that authenticates over OAuth2 with a Keycloak 17 instance running in Docker.

Everything works fine when I start the app locally from Intellij.

But when I run the app from a Docker container with docker-compose I get:

[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: I/O error on POST request for "http://localhost:80/realms/Demo/protocol/openid-connect/token": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)

when I input the credentials on the keycloak login page. But there is a session created for that user in keycloak.

System:

  • MacBook with Monteray 12.0.1
  • Docker Desktop 4.5 with Kubernetes 1.22.5

docker-compose.yml

version: '3.9'

networks:
  network_keycloak_postgres_app:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"

volumes:
  keycloak_postgres_data:
    driver: local

services:
  postgres:
    container_name: postgres
    image: postgres
    volumes:
      - keycloak_postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak_db_admin
      POSTGRES_PASSWORD: keycloak_db_password
    ports:
      - "5432:5432"
    networks:
      - network_keycloak_postgres_app

  keycloak:
    container_name: keycloak
    hostname: keycloak
    image: quay.io/keycloak/keycloak:17.0.0
    command: ["start-dev", "--log-level=debug"]
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: change_me
      KC_DB: postgres
      KC_DB_USERNAME: keycloak_db_admin
      KC_CACHE: local
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_PASSWORD: keycloak_db_password
    ports:
      - "80:8080"
      - "443:8443"
    depends_on:
      - postgres
    networks:
      - network_keycloak_postgres_app

  demo_app:
    container_name: demo_app
    hostname: demoapp
    build:
      context: ../
      dockerfile: Dockerfile
    environment:
      SPRING_PROFILES_ACTIVE: default
    ports:
      - "4242:4242"
    depends_on:
      - keycloak
    networks:
      - network_keycloak_postgres_app

Dockerfile (made sure to run 'mvn clean package' before build)

FROM openjdk:11.0.11-jre-slim
COPY ./target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar
EXPOSE 4242
ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"]

application.yml

server:
  port: 4242

logging:
  level:
    root: DEBUG
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG
    # org.springframework.boot.autoconfigure: DEBUG

spring:
  thymeleaf:
    cache: false
  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: demo-app
            client-secret: 5cuxTUgiLJATP4pMpw7j8HZieekdOBsM
            client-name: Keycloak
            authorization-grant-type: authorization_code
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            scope:
              - openid
              - profile
              - email
        provider:
          keycloak:
            authorization-uri: http://localhost:80/realms/Demo/protocol/openid-connect/auth
            token-uri: http://localhost:80/realms/Demo/protocol/openid-connect/token
            user-info-uri: http://localhost:80/realms/Demo/protocol/openid-connect/userinfo
            jwk-set-uri: http://localhost:80/realms/Demo/protocol/openid-connect/certs
            user-name-attribute: preferred_username

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.kressing</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Spring Security 5 OAuth2 Client and Keycloak sample</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>


        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>

        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.htmlunit</groupId>
            <artifactId>htmlunit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

What I have already tried:

  • giving the app and keycloak container hostnames
  • running the app container in another docker-compose
  • using "http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:8080" instead of localhost
  • using other openjdk image to build from

Thanks in advance for any hints and help!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source